2013-05-12 83 views
4

this問題的答案是什麼是Bash中的流量控制?

find . -type f -name \*.mp4 -exec sh -c 'ffprobe "$0" 2>&1 | 
    grep -q 1920x1080 && echo "$0"' {} \; 

將輸出是1920x1080所有的MP4文件。

我不明白爲什麼sh -c在那裏。如果我刪除它,那麼它不會找到任何東西。

作者說

新的外殼需要處理exec'd 命令裏面的流量控制。

但我想我錯過了一些基本知識來理解答案。

問題

任何人都可以解釋爲什麼sh -c必須在那裏,爲什麼它只然後ffprobe在一個新的外殼打開?

回答

6

-exec選項需要的參數的順序:

find . -exec arg0 arg1 arg2 ... \; 

如果加上引號

find . -exec "arg0 arg1 arg2" \; 

然後 「爲arg0 ARG1 ARG2」 被視爲一個參數的參數。可以預期帶有空格的arg0 arg1 arg2命令將存在於您的系統中,而不是名爲arg0的參數爲arg1arg2的命令。

如果你使用發現沒有sh -c,那麼你就會有這樣的:

find . -type f -name \*.mp4 -exec 'ffprobe "{}" 2>&1 | 
    grep -q 1920x1080 && echo "{}"' \; 

這意味着find會尋找一個叫做ffprobe "$0" ....命令,傳遞沒有參數 - 有沒有這樣的命令。有一個叫做ffprobe的命令,它帶有參數,這就是你需要的。一種可能性是做這樣的事情:

find . -type f -name \*.mp4 -exec ffprobe '$0' 2>&1 | 
    grep -q 1920x1080 && echo '{}' \; 

然而,這是不行的,因爲輸出重定向2>&1和管道|和命令序列算&&都會比你想要的東西區別對待。

爲了解決這個問題,他們使用另一個shell。這類似於創建一個腳本做的工作:

find . -type f -name \*.mp4 -exec myscript {} \; 

但不是一個單獨的腳本,一切都在一行上。

+1

部分原因也是由於'unistd.h'中的'exec *'函數造成的。很有可能(我還沒有讀過GNU find的源代碼),他們使用的是類似execve的東西,所以你是正確的,因爲這些函數的第一個參數必須是二進制(可執行文件)才能運行。該字符串將被視爲一個大的可執行文件,並會導致錯誤。它們大部分(如果不是全部的話)會爲傳遞的其餘參數採用一個字符串數組或可變數量的參數。 – 2013-05-12 16:31:30

+0

我真的很驚訝$ 0被解釋爲它在單引號內。爲什麼這個工作? – 2013-05-12 17:12:51

+1

@SandraSchlichting:'$ 0'在另一個shell內部被替換,它看不到單引號。 – 2013-05-12 17:15:50

5

find執行給予exec參數作爲直接的命令(即它調用的第一個參數爲帶有以下參數作爲參數傳遞給該命令的應用程序),而不大於與文件名稱替換{}做在其上的任何處理其他。也就是說,它沒有實現任何shell特性,如管道或輸入重定向。在你的情況下,該命令包含管道和輸入重定向。所以你需要通過sh運行命令,以便sh可以處理這些命令。

1

區別在於執行find。 Find使用Linux/Unix(Posix)調用fork()exec()的調用來產生一個新進程並將帶有參數的命令傳遞給它。 exec()調用運行可執行文件(二進制文件或shebang解釋程序),將參數直接作爲參數字符串傳遞給它。沒有對這些參數進行處理。

因此,不會解釋shell約定。例如。 $0,2>&1和'|'等等作爲參數傳遞給​​。不是你想要的。通過添加sh -c,您告訴find執行一個shell,將其餘的行傳遞給它以供解釋。

請注意,通過將命令放入shebang腳本並從find調用此腳本,可以獲得相同的效果。這裏exec'ed腳本會加載shell。