Protecting arguments containing spaces from eval Protecting arguments containing spaces from eval unix unix

Protecting arguments containing spaces from eval


Original question

For your preferred use-case, you'd simply write (inside my_command):

"$@"

to execute the command as given.

Your eval line is odd:

eval 'sed 's/foo/foo'" "'bar/g' filename'

Because of the way single quotes don't nest, it is equivalent to:

 eval 'sed s/foo/foo" "bar/g filename'

Revised question

Possible solution:

egrep '/.*/' filename | sh

This feeds what is in filename directly to the shell for interpretation. Given file containing:

Some text containing foo; and bar.More foo bar?More text; more foo and bar; more foo bar beyond the possibility of unfooing.

The output is:

Some text containing foo bar; and bar.More foo bar bar?More text; more foo bar and bar; more foo bar bar beyond the possibility of unfoo baring.

Fixing quotes is hard!

Note that your complex sed script is not complex enough. Given filename containing:

sed 's/foo/foo bar/g' filesed 's/foo bar/foo bar baz/g' file

the output from:

egrep '/.*/' filename |sed 's/\(.*\)['"'"']\(.*\) \(.*\)['"'"']\(.*\)/\1'"\'"'\2" "\3'"\'"'\4/g'

is:

sed 's/foo/foo" "bar/g' filesed 's/foo bar/foo bar" "baz/g' file

which has not solved all the problems for the eval.

I've spent a lot of time, on and off, working on such issues over quite a long period of time (a quarter century is no exaggeration), and it isn't trivial. You can find one discussion in extenso in How to iterate over arguments in bash script. Somewhere, I have another answer which goes through gyrations about this stuff, but I can't immediately find it (where 'immediately' means an hour or so of distracted searching, where the distractions were sets of duplicate questions, etc). It may have been deleted, or I may have looked in the wrong place.


your design is flawed. Create a user interface that doesn't let them input commands directly. give options, or let them enter the parameters only.At the back end, you do your sanitization check on the parameters before calling sed or other tools desired. You don't have to use eval


Array quoting

The following keeps spaces in arguments by quoting each element of array:

function token_quote {  local quoted=()  for token; do    quoted+=( "$(printf '%q' "$token")" )  done  printf '%s\n' "${quoted[*]}"}

Example usage:

$ token_quote token 'single token' tokentoken single\ token token

Above, note the single token's space is quoted as \.

$ set $(token_quote token 'single token' token)$ eval printf '%s\\n' "$@"tokensingle tokentoken$

This shows that the tokens are indeed kept separate.


Given some untrusted user input:

% input="Trying to hack you; date"

Construct a command to eval:

% cmd=(echo "User gave:" "$input")

Eval it, with seemingly correct quoting:

% eval "$(echo "${cmd[@]}")"User gave: Trying to hack youThu Sep 27 20:41:31 +07 2018

Note you were hacked. date was executed rather than being printed literally.

Instead with token_quote():

% eval "$(token_quote "${cmd[@]}")"User gave: Trying to hack you; date%

eval isn't evil - it's just misunderstood :)