commit c75cbff329e706e955d8f3e353628c7d950b6ca5 Author: Nero <41307858+nero@users.noreply.github.com> Date: Sun Sep 11 14:51:37 2022 +0000 Finalize project diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9ff241a --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +PROGS = sh_quote +CFLAGS = -std=c99 -pedantic + +default: $(PROGS) + +test: $(PROGS) + ./test_sh_quote + +clean: + rm -f $(PROGS) diff --git a/README.md b/README.md new file mode 100644 index 0000000..265b5e7 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Shell quoting util + +This tool was made to handle a specific edge case in shell scripting. + +When you want to supply a command to some tool as a shell string, but you only have it as already expanded array. + +This doesn't work as expected because `$@` is expanded, ending up as multiple arguments to `su`: + +``` +su -c "$@" +``` + +This does work as expected: + +``` +su -c "$(sh_quote "$@")" +``` + +Because all arguments must be relayed, `-h` or `--help` cannot be taken into account, so there is no helptext. + +When no arguments are given, it returns without producing any output. + +# Error messages + +None. This program cannot fail. + +If stdout is not writable, no sensible output will be generated. + +If `$0` is not set, no output will be generated. + +# Building + +Run `make`. + +# Testing + +Run `make test` + +The test script can also run on arbitrary programs: `./run_sh_quote /path/to/other_program`. diff --git a/sh_quote.c b/sh_quote.c new file mode 100644 index 0000000..f94ddef --- /dev/null +++ b/sh_quote.c @@ -0,0 +1,26 @@ +#include +#include + +int main(int argc, char** argv) { + unsigned int i; + char* p; + char* delim = "'"; + for (i = 1; i < argc; i++) { + if (i > 1) putchar(' '); + p = argv[i]; + + printf("%s", delim); + while(*p != '\0') { + if (p[0] == '\'') { + printf("%s\\'%s", delim, delim); + p++; + continue; + } + if (p[0] == '\\') putchar('\\'); + putchar((p++)[0]); + } + printf("%s", delim); + } + putchar('\n'); + return 0; +} diff --git a/test_sh_quote b/test_sh_quote new file mode 100755 index 0000000..4d42108 --- /dev/null +++ b/test_sh_quote @@ -0,0 +1,20 @@ +#!/bin/sh +PROG=${1:-./sh_quote} + +run_test() { + r=$($PROG "$2"|sed 's/^ *//;s/ *$//') + if test "$r" == "$3"; then + echo PASS "$1" + else + echo FAIL "$1" + printf "Expected: %s\nGot: %s\n" "$3" "$r" + fi +} + +run_test empty "" "''" +run_test whitespace "Foo Bar" "'Foo Bar'" +run_test quote "Foo'Bar" "'Foo'\''Bar'" +run_test newline "Foo +Bar" "'Foo +Bar'" +run_test trailing_space "Foobar " "'Foobar '"