Bash:命令替換中的引用

Bash:命令替換中的引用

簡而言之,我想在命令中使用命令列出的目錄find

find $(produces_dir_names --options...) -find-options...

問題在於目錄名稱中存在空格。我認為在生成命令的輸出中引用它們(我可以更改)就足夠了:

"a" "a b" "a b c"

但 bash 抱怨道:

find: ‘"a"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b’: No such file or directory
find: ‘c"’: No such file or directory

如您所見, seebash會在空格上分割指令的輸出,即使使用引號也是如此。我嘗試擺弄IFS並將其設置為\n,但我對它的理解似乎太有限,無法使其正常工作。

我發現的唯一解決方法是在這個 Stack Overflow 問題中: bash指令取代刪除引號,即eval在它前面放一個,但這看起來有點難看。

我的問題:

有沒有一種簡單的方法以及在沒有 的情況下編寫此替換會是什麼樣子eval

報價還有必要嗎?

範例(產生相同的輸出):

find $(echo '"a" "a b" "a b c"')

答案1

也許分兩行

IFS=$'\n' DIRS=( $(produces_dir_names --options...) ) 
find "${DIRS[@]}" -find-options...

例子:

$ mkdir -p "/tmp/test/a b/foo" "/tmp/test/x y/bar"

$ IFS=$'\n' DIRS=( $(printf "/tmp/test/a b\n/tmp/test/x y\n") )
$ find "${DIRS[@]}" -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar

但總的來說,這不是一個好的風格。例如,如果您的 DIRS 包含換行符,您就會遇到麻煩。更好地修復您的“ Produces_dir_names”以列印空字節終止的字串。關於我的例子,這將是這樣的:

$ printf "/tmp/test/a b\0/tmp/test/x y\0" | xargs -0 -I '{}' find '{}' -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar

如果您無法修復“products_dir_names”,則關於我的最後一條評論,最通用的解決方案將如下所示:

produces_dir_names --options... | tr '\n' '\0' | xargs -0  -I '{}' find '{}' -find-options...

除非您修復“ Produces_dir_names”以避免“換行符號”,否則“換行符號”仍然存在問題tr

答案2

魯迪邁爾的回答很好——具體來說,關於修改produces_dir_names 以打印空終止字串的部分——但從他的回答中可能並不明顯看出它find為每個目錄執行一次。如果這足夠好,那就好了。但是,當然,可以使用find 多個起點進行呼叫;例如,

尋找  目錄1目錄2目錄3  -尋找選項...

從問題看來這就是你想要的。這可以如下完成:

printf "a\0a b\0a b c" | printf "a\0a b\0a b c" | xargs -0 sh -c '查找“$@”-尋找選項...' 什

這會導致xargs呼叫sh -c一次,並將所有目錄名稱附加到命令中。然後 shell 將會展開"$@"為這些目錄名稱的清單。

PS 如果produces_dir_names列出太多目錄名稱而無法放在一個命令列上,則將xargs被迫產生一些命令。用於xargs --verbose查看xargs正在產生哪些命令。

答案3

只是為了揭開您收到的錯誤訊息的神秘面紗:

find: ‘"a"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b’: No such file or directory
find: ‘c"’: No such file or directory

答案是Bash 引號刪除不會刪除以下引號結果來自命令替換。

LESS='+/^ *Quote Removal' man bash

Quote Removal
    After the preceding expansions, all unquoted occurrences of the charac-
    ters  \,  ', and " that did not result from one of the above expansions
    are removed.

引用的「前述擴展」包括:

EXPANSION
   Brace Expansion
   Tilde Expansion
   Parameter Expansion
   Command Substitution
   Arithmetic Expansion
   Process Substitution
   Word Splitting
   Pathname Expansion
   Quote Removal

相關內容