Input 1:

find . -maxdepth 1 -name "* *" -exec bash -c 'sed -n '1p' <(echo $1)' h {} \;

Output 1:

./file with space

Input 2:

find . -maxdepth 1 -name "* *" -exec bash -c 'sed "1s_ _._" <(echo $1)' h {} \;

Output 2:


Input 3:

find . -maxdepth 1 -name "* *" -exec bash -c 'sed '1s_ _o_' <(echo $1)' h {} \;

Output 3:

sed: -e expression #1, char 3: unterminated `s' command

Why is the Output 3 an error? how does the single and double quote make a difference in this scenario?


After the parsing performed by the outer shell, the third command consists of the words find, ., -maxdepth, 1, -name, * *, -exec, bash, -c, sed 1s_, _o_ <(echo $1), h, {}, ;. The word sed 1s_ is a single argument since the space is within a single-quoted literal, and likewise for the next argument. Thus, when find reaches ./file with space, it runs bash with the arguments -c, sed 1s_, _o_ <(echo $1), h, ./file with space. The shell script sed 1s_ is the command sed with the argument 1s_, and this is not a well-formed sed script.

You attempted to put a single-quoted string inside a single-quoted string, but that isn't possible: the second single quote ends the single-quoted string. You could use '\'' to end the single-quoted literal, then put a literal single quote, and start a single-quoted literal again:

find . -maxdepth 1 -name "* *" -exec bash -c 'sed '\''1s_ _o_'\'' <(echo $1)' h {} \;

Of course <(echo $1) breaks on file names containing wildcard characters or whitespace sequences other than a single space. I have no idea why you wrote that instead of <<<"$1".

  • Thanks for having the patience and explaining this way. Learned a lot. – boobalan Jan 30 '17 at 2:24

I guess it is because you are closing the single quote used for the bash command -c option.

So, you are running: bash, with first argument -c, second argument sed 1s_, third argument _o_ <(echo $1) and so on. Something like the following:

$ bash -c 'sed 1s_' '_o_ <(echo $1)'

The third argument ('_o_ <(echo $1)') is passed to bash, not to sed.

To fix your command, you should use double quotes for the sed argument:

$ find . -maxdepth 1 -name "* *" -exec bash -c 'sed "1s_ _o_" <(echo $1)' h {} \;
  • How did $ bash -c 'sed '1s_ o' <(echo $1)' became $ bash -c 'sed 1s_' 'o' <(echo $1) as you mentioned. – boobalan Jan 29 '17 at 23:55
  • 1
    @boobalangnanasekaran You can't nest single quotes ('). – phk Jan 29 '17 at 23:59
  • Reading it more carefully, the third argument is _o_ <(echo $1). Fixed in the answer. – zuazo Jan 29 '17 at 23:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.