Skip to main content
added 311 characters in body
Source Link
Matt Alexander
  • 755
  • 1
  • 8
  • 20

Creating shell command strings

Useful for joining multiple arguments into a single string when you want to run them through a sh -c command.

Before:Before:

After:After:

Ugly, but. Reliable. Just how I like it works. :-)

_dumpargs() {  printf '[%s]' "$@";"$@"  printf '\n';printf '\n' } >&2 
dumpargs_dumpargs one two three # [one][two][three] dumpargs_dumpargs one 'two three' # [one][two three] dumpargs_dumpargs one two\ three # [one][two three] dumpargs_dumpargs cat 'aw ful".txt' # [cat][aw ful".txt] dumpargs_dumpargs "$(_shlexjoin cat 'aw ful".txt')" # ['cat' 'aw ful".txt']   #  ^ One arg, looks like two ^ 
_shlexjoin one 'two three' # _shlexjoin()  { echo ${*@Q}; } # From above  # Output: 'one' 'two three' _shlexjoin_pr one 'two three' # _shlexjoin_pr() { printf ' %q' "$@"# |Output: cutone -b2-;two\ }three _shlexjoin.py_shlexjoin_py one 'two three' # _shlexjoin_py() { python3 -c 'import sys,shlex;print(shlex.join(sys.argv[1:]))' "$@"; } # Output: one two\'two threethree' 

Useful for joining multiple arguments into a single string when you want to run them through a sh -c command.

Before:

After:

Ugly, but it works.

_dumpargs() { printf '[%s]' "$@"; printf '\n'; } 
dumpargs one two three # [one][two][three] dumpargs one 'two three' # [one][two three] dumpargs one two\ three # [one][two three] dumpargs cat 'aw ful".txt' # [cat][aw ful".txt] dumpargs "$(_shlexjoin cat 'aw ful".txt')" # ['cat' 'aw ful".txt']   #  ^ One arg, looks like two 
_shlexjoin one 'two three' # _shlexjoin()  { echo ${*@Q}; } # From above  # Output: 'one' 'two three' _shlexjoin_pr one 'two three' # _shlexjoin_pr() { printf ' %q' "$@" | cut -b2-; } _shlexjoin.py one 'two three' # _shlexjoin_py() { python3 -c 'import sys,shlex;print(shlex.join(sys.argv[1:]))' "$@"; } # Output: one two\ three 

Creating shell command strings

Useful for joining multiple arguments into a single string when you want to run them through a sh -c command.

Before:

After:

Ugly. Reliable. Just how I like it. :-)

_dumpargs() {  printf '[%s]' "$@"  printf '\n' } >&2 
_dumpargs one two three # [one][two][three] _dumpargs one 'two three' # [one][two three] _dumpargs one two\ three # [one][two three] _dumpargs cat 'aw ful".txt' # [cat][aw ful".txt] _dumpargs "$(_shlexjoin cat 'aw ful".txt')" # ['cat' 'aw ful".txt'] # One arg, looks like two ^ 
_shlexjoin one 'two three' # Output: 'one' 'two three' _shlexjoin_pr one 'two three' # Output: one two\ three _shlexjoin_py one 'two three' # Output: one 'two three' 
added 311 characters in body
Source Link
Matt Alexander
  • 755
  • 1
  • 8
  • 20

By the wayNon-Bash alternatives

_shlexjoin_p_shlexjoin_pr() {  printf ' %q' "$@" | cut -b2-; } 

Or if python's handy, you could do this:

_shlexjoin_py() { python3 -c 'import sys,shlex;print(shlex.join(sys.argv[1:]))' "$@" } 

It worksThey each work differently, but it'sthey are functionally equivalent:

_shlexjoin  one 'two three'  # _shlexjoin()  { echo ${*@Q}; } # From above  # Output: 'one' 'two three' _shlexjoin_p_shlexjoin_pr one 'two three'  # _shlexjoin_p_shlexjoin_pr() { printf ' %q' "$@" | cut -b2-; } _shlexjoin.py one 'two three' # _shlexjoin_py() { python3 -c 'import sys,shlex;print(shlex.join(sys.argv[1:]))' "$@"; } # Output: one two\ three 

By the way

_shlexjoin_p() { printf ' %q' "$@" | cut -b2-; } 

It works differently, but it's functionally equivalent:

_shlexjoin one 'two three'  # _shlexjoin() { echo ${*@Q}; } # Output: 'one' 'two three' _shlexjoin_p one 'two three'  # _shlexjoin_p() { printf ' %q' "$@" | cut -b2-; } # Output: one two\ three 

Non-Bash alternatives

_shlexjoin_pr() {  printf ' %q' "$@" | cut -b2- } 

Or if python's handy, you could do this:

_shlexjoin_py() { python3 -c 'import sys,shlex;print(shlex.join(sys.argv[1:]))' "$@" } 

They each work differently, but they are functionally equivalent:

_shlexjoin  one 'two three' # _shlexjoin()  { echo ${*@Q}; } # From above  # Output: 'one' 'two three' _shlexjoin_pr one 'two three' # _shlexjoin_pr() { printf ' %q' "$@" | cut -b2-; } _shlexjoin.py one 'two three' # _shlexjoin_py() { python3 -c 'import sys,shlex;print(shlex.join(sys.argv[1:]))' "$@"; } # Output: one two\ three 
Source Link
Matt Alexander
  • 755
  • 1
  • 8
  • 20

This is what I use:

_shlexjoin() { echo ${*@Q} } 
Bash feature Action
Special parameter $*, unquoted "Each positional parameter expands to a separate word"
${parameter@operator} using Q operator Each parameter is "quoted in a format that can be reused as input"

Useful for joining multiple arguments into a single string when you want to run them through a sh -c command.

Before:

cat 'aw ful".txt' # Output: Hello world! 

After:

command_string=$(_shlexjoin cat 'aw ful".txt') sh -c "${command_string}" # Output: Hello world! 

Printing runnable commands or writing commands to scripts

Before printing ${command_string} to your terminal or writing it to a script, you'll need to escape it again, which you can do by running it through the same function:

inception=$(_shlexjoin "${command_string}") echo "sh -c ${inception}" # Output: sh -c ''\''cat'\'' '\''aw ful".txt'\''' 

Ugly, but it works.

Debugging

If, on the other hand, you just need to see how the arguments are being split, it's way easier to use something like this:

_dumpargs() { printf '[%s]' "$@"; printf '\n'; } 
dumpargs one two three # [one][two][three] dumpargs one 'two three' # [one][two three] dumpargs one two\ three # [one][two three] dumpargs cat 'aw ful".txt' # [cat][aw ful".txt] dumpargs "$(_shlexjoin cat 'aw ful".txt')" # ['cat' 'aw ful".txt'] # ^ One arg, looks like two 

By the way

You mention bash, but if you want a functionally equivalent solution that is not bash-specific and you don't mind creating processes, you can use printf's %q format:

_shlexjoin_p() { printf ' %q' "$@" | cut -b2-; } 

It works differently, but it's functionally equivalent:

_shlexjoin one 'two three' # _shlexjoin() { echo ${*@Q}; } # Output: 'one' 'two three' _shlexjoin_p one 'two three' # _shlexjoin_p() { printf ' %q' "$@" | cut -b2-; } # Output: one two\ three