How does /bin/bash -c differ from executing a command directly?

后端 未结 2 1749
南笙
南笙 2021-01-17 17:18

I\'m curious why the commmand:

for f in `/bin/ls /mydir | sort | tail -n 10`; do echo $f; done;

Outputs the last ten files in /mydir, but

相关标签:
2条回答
  • 2021-01-17 18:04

    You are using double-quotes, so the parent shell is interpolating backticks and variables before passing the argument to /bin/bash.

    Thus, your /bin/bash is receiving the following arguments:

    -c "for f in x
    y
    z
    ...
    ; do echo ; done;"
    

    which is a syntax error.

    To avoid this, use single quotes to pass your argument:

    /bin/bash -c 'for f in `/bin/ls /mydir | sort | tail -n 10`; do echo $f; done;'
    
    0 讨论(0)
  • 2021-01-17 18:05

    Different newline handling in your subcommand output. For example on my machine, using /bin I get this output for your first example:

    rmdir
    sh
    sleep
    stty
    sync
    tcsh
    test
    unlink
    wait4path
    zsh
    

    But with the latter:

    /bin/bash: -c: line 1: syntax error near unexpected token `sh'
    /bin/bash: -c: line 1: `sh'
    

    Because the command substitution takes place in your first shell in both cases, your first one works (the newlines are stripped out when making the command line), but in the second case it doesn't - they remain in the string thanks to your "". Using echo rather than bash -c can showcase this:

    $ echo "for f in `/bin/ls /bin | sort | tail -n 10`; do echo \$f; done"
    for f in rmdir
    sh
    sleep
    stty
    sync
    tcsh
    test
    unlink
    wait4path
    zsh; do echo $f; done
    

    You can see from that what your bash -c is seeing and why it doesn't work - the sh comes before the do!

    You can use single quotes instead, but that will cause the subcommand to run in your new subshell:

    $ /bin/bash -c 'for f in `/bin/ls /bin | sort | tail -n 10`; do echo $f; done'
    rmdir
    sh
    sleep
    stty
    sync
    tcsh
    test
    unlink
    wait4path
    zsh
    

    If that's not ok, you need to get rid of those newlines:

    $ /bin/bash -c "for f in `/bin/ls /bin | sort | tail -n 10 | tr '\n' ' '`; do echo \$f; done"
    rmdir
    sh
    sleep
    stty
    sync
    tcsh
    test
    unlink
    wait4path
    zsh
    
    0 讨论(0)
提交回复
热议问题