並行變數聲明 sh -c …
我一直在嘗試處理
find
with的輸出parallel
,這反過來又呼叫了一個 shell(需要一些文本替換)。我觀察到一些奇怪的行為,我無法對自己真正解釋。在每個目錄中都有一堆文件,稱它們為
file1.xtc
,file2.xtc
. 其中一些具有諸如file1.part0002.xtc
等的名稱。如果傳遞的文件find
具有*.part000x.*
名稱,我需要刪除該*.part000x.*
位,以便生成的命令類似於command -f file1.part0001.xtc -s file1.tpr
我使用了
find
andparallel
來達到這個效果,但是parallel
’ 的替換(特別是{.}
位)還不夠(他們刪除了.xtc
副檔名,只剩下.part0001
一個),所以這是我用來檢查輸出的命令:find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name=""; name="{.}"; echo {.} ${name%.*}.tpr'
如果我使用上面的命令,首先聲明
name
並分配一個空字元串(或其他任何東西),結果是file1.part0001 file1.tpr
根據需要(這些是我需要用於我的命令的名稱)。但是,如果我執行這個
find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name="{.}"; echo {.} ${name%.*}.tpr'
結果是:
file1.part0001 .tpr
或者它表現得好像
$name
不存在一樣。所以我的問題是:
這種行為的原因是什麼?
處理它的首選方法是什麼?
第一個問題在這裡更重要,因為我上面使用的方法是一種解決方法,雖然不是很漂亮,但很有效。這不是我第一次需要進行這樣的文本替換,這種行為繼續讓我感到困惑。
的輸出
sh --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
我安裝和使用的更新版本的輸出,
bash
而不是sh
在上面的命令中(效果相同)(/usr/local/bin/bash --version
)GNU bash, version 4.2.0(1)-release (i386-apple-darwin11.4.2)
您的問題與 bash 無關。事實上,既然你告訴
parallel
執行sh
,你甚至可能沒有使用bash
.問題在於,parallel 並不是 xargs 的真正替代品,正如其文件所示。相反,它將其參數累積到一個字元串中(它們之間有空格),然後將其解釋為一系列命令。所以,在你的情況下,你有:
sh -c 'name="{.}"; echo {.} ${name%.*}.tpr'
這被解釋為
sh -c 'name="{.}"; echo {.} ${name.*}.tpr
由於這些是兩個單獨的命令,並且第一個命令在子 shell (
sh -c
) 中執行,$name
因此未在第二個命令中設置。現在,您可以在字元串的開頭添加任何內容,例如
true
:sh -c 'true; name="{.}"; echo {.} ${name%.*}.tpr'
這將被解釋為:
sh -c 'true' name="{.}" echo {.} ${name%.*}.tpr'
在這種情況下,呼叫
sh
本質上是一次性的;thenname
在由parallel
and finally維護的環境中設置,並echo
使用 set 呼叫name
。所以看起來最簡單的解決方案就是擺脫不必要的呼叫
sh
:find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 'name={.}; echo {.} "${name%.*}.tpr"'
*注意:*根據@StephaneChazelas 給出的提示,我刪除了周圍的引號
{.}
並將它們添加到${name%.*}.ptr
. parallel 對自己的替換進行了自己的引用,這以一些奇怪的方式乾擾了顯式引用。但是,它不會在 shell 替換中添加引號,如果替換存在分詞的任何可能性,則應將其引用。如果您出於某種原因(或特定的子shell)確實想使用子shell,另一種選擇是使用以下
-q
選項:find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 -q sh -c 'name="{.}"; echo "{.}" "${name%.*}.tpr"'
*注意:*如上所述,我調整了引號。在這種情況下,顯式
-q
禁止引用替換,因此您必須顯式引用它們。但是,這是文本引用,不如 shell 引用準確;如果替換包含雙引號字元,則該字元不會被轉義,因此它將關閉顯式引號,破壞命令行並有效地引入命令注入漏洞(文件名包含$
,```或\
人物)。為此,除其他原因外,-q
不鼓勵該選項。