eval 和 exec 有什麼區別?
eval
並且exec
都內置在執行命令的 bash(1) 命令中。我也看到
exec
有一些選擇,但這是唯一的區別嗎?他們的背景會發生什麼?
eval``exec
是完全不同的野獸。(除了兩者都將執行命令這一事實之外,您在 shell 中所做的一切也是如此。)$ help exec exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...] Replace the shell with the given command.
做什麼
exec cmd
,與 running 完全相同,只是cmd
目前 shell 被替換為命令,而不是執行一個單獨的程序。在內部,執行say/bin/ls
會呼叫fork()
創建一個子程序,然後exec()
在子程序中執行/bin/ls
。exec /bin/ls
另一方面不會分叉,而只是替換外殼。比較:
$ bash -c 'echo $$ ; ls -l /proc/self ; echo foo' 7218 lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7219 foo
和
$ bash -c 'echo $$ ; exec ls -l /proc/self ; echo foo' 7217 lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7217
echo $$
列印我啟動的 shell 的 PID,並且列出從 shell 執行/proc/self
的 PID 。ls
通常,程序 ID 不同,但與exec
shellls
具有相同的程序 ID。此外,以下命令exec
沒有執行,因為 shell 已被替換。另一方面:
$ help eval eval: eval [arg ...] Execute arguments as a shell command.
eval
將在目前 shell 中將參數作為命令執行。換句話說eval foo bar
就是和剛才一樣foo bar
。但是變數在執行前會被展開,所以我們可以執行保存在shell變數中的命令:$ unset bar $ cmd="bar=foo" $ eval "$cmd" $ echo "$bar" foo
它不會創建子程序,因此變數是在目前 shell 中設置的。(當然
eval /bin/ls
會創建一個子程序,就像普通的舊程序一樣/bin/ls
。)或者我們可以有一個輸出 shell 命令的命令。執行
ssh-agent
在後台啟動代理,並輸出一堆變數分配,可以在目前 shell 中設置並由子程序(ssh
您將執行的命令)使用。因此ssh-agent
可以開始:eval $(ssh-agent)
並且目前的shell會獲取其他命令繼承的變數。
當然,如果變數
cmd
碰巧包含類似的東西rm -rf $HOME
,那麼執行eval "$cmd"
就不是你想做的事情。即使是字元串中的命令替換之類的東西也會被處理,所以在使用它之前應該確保輸入是eval
安全的。通常,
eval
可以避免甚至避免以錯誤的方式意外混合程式碼和數據。