layout: post title: 神秘的bash -c選項 categories:
某天在執行命令盯著螢幕看的時候,發現一行有趣的指令,大致如下...
num@instance-1:~$ ssh remote-1 "ps -ef | grep bash"
ubuntu 25570 25569 0 02:50 ? 00:00:00 bash -c ps -ef | grep bash
ubuntu 25572 25570 0 02:50 ? 00:00:00 grep bash
透過ssh發給遠端主機的命令中,夾帶了一個-c
,在man中的解釋為
-c If the -c option is present, then commands are read from the first non-option argument command_string.
If there are arguments after the command_string, they are assigned to the positional
parameters, starting with $0.
一般使用以下指令都是正常的
bash -c 'w'
bash -c 'ls'
bash -c 'echo hello world'
那如果後面繼續帶參數呢...就沒有反應了
$ bash -c 'echo hello world' xxx yyy zzz
hello world
上網四處逛逛,看到了一篇類似文章
這開始令人不解了...用那麼久沒看過指令這樣下的
num@instance-1:~$ ssh localhost bash -c "echo hello world" true
num@instance-1:~$ ssh localhost bash -c "echo hello world"
num@instance-1:~$ ssh localhost bash -c "true; echo hello world"
hello world
所以這個神奇的參數到底在作什麼,哪來的-c
又true
的,後來又找到一篇
先撇開ssh這件事,看看-c
搞什麼名堂
試著跑了一次
num@instance-1:~$ bash -c 'echo "$0 is $0, $1 is $1, $2 is $2"' foo bar biz
foo is foo, bar is bar, biz is biz
test.sh檔案內容
num@instance-1:~$ cat test.sh
#!/bin/bash
echo "$0 is $0, $1 is $1, $2 is $2"
echo $*
存成檔案再跑一次
num@instance-1:~$ bash -c './test.sh' foo bar biz
./test.sh is ./test.sh, is , is
直接執行的話,結果是這樣
num@instance-1:~$ ./test.sh foo bar biz
./test.sh is ./test.sh, foo is foo, bar is bar
太令人混亂了。於是我換了一個方法,直接在執行指令處印出args:
num@instance-1:~$ bash -c 'echo "$@"' aaa bbb ccc
bbb ccc
num@instance-1:~$ ./test.sh aaa bbb ccc
./test.sh is ./test.sh, aaa is aaa, bbb is bbb
aaa bbb ccc
num@instance-1:~$ bash -c './test.sh' aaa bbb ccc
./test.sh is ./test.sh, is , is
結果顯示,使用bash -c
時,是把後面的args都傳給bash
自身,而不是傳給-c
裡面的命令
那麼回到剛開始的ssh localhost bash -c這個問題..
我們已經知道執行ssh remote1 echo hello world的時候,實際上ssh會到remote1這台機器執行
bash -c "echo hello world"
所以前面的指令帶換後也會產生一樣的結果
num@instance-1:~$ bash -c "bash -c "echo hello world" true"
num@instance-1:~$ bash -c "bash -c "echo hello world""
num@instance-1:~$ bash -c "bash -c "true; echo hello world""
hello world