tmux new-window
passes a command to a shell. This is good, your command is a pipeline and you need a shell to process it. But this means there will be a shell that will take your command as a string and only then interpret it (like sh -c
does).
It seems tmux new-window
(like ssh
) can built a command string for the inner (in case of ssh
: remote) shell from multiple arguments it gets. For these tools I prefer giving a single argument nevertheless.
You need to quote for that inner shell; at the same time you need to quote for the outer shell that interprets the script. In other words you need to craft the whole tmux command, so after the outer shell substitutes $1
and removes quotes it doesn't take literally, the string(s) passed to tmux new-window
forms a shell command where everything that needs to be quoted is properly quoted for the inner shell.
An obvious idea is to embed some additional quotes. This is flawed though:
# flawed, don't
tmux new-window "pdftotext -layout -nopgbrk \"${1}\" - | less"
# also flawed, don't
tmux new-window "pdftotext -layout -nopgbrk '${1}' - | less"
An argument containing "
, $
, `
, \
, !
or '
will break one command and/or the other. Worse, this creates a code injection vulnerability (i.e. for an unfortunate or rogue argument, your script will execute a part of the argument as shell code).
Your script uses Bash. We can ask Bash itself to expand $1
to a quoted form in a safe way. This is done by the Q
modifier:
#!/bin/bash
tmux new-window "pdftotext -layout -nopgbrk ${1@Q} - | less"
No matter what $1
expands to, the outer shell will expand ${1@Q}
to a form that will look properly quoted to the inner shell.
"pdftotext -layout -nopgbrk "
is one quoted string,$1
(the braces don't matter here) is unquoted, and" - | less"
is again quoted. – muru Nov 06 '23 at 08:12