Bash

並行變數聲明 sh -c …

  • September 13, 2017

我一直在嘗試處理findwith的輸出parallel,這反過來又呼叫了一個 shell(需要一些文本替換)。我觀察到一些奇怪的行為,我無法對自己真正解釋。

在每個目錄中都有一堆文件,稱它們為file1.xtc, file2.xtc. 其中一些具有諸如file1.part0002.xtc等的名稱。如果傳遞的文件find具有*.part000x.*名稱,我需要刪除該*.part000x.*位,以便生成的命令類似於

command -f file1.part0001.xtc -s file1.tpr 

我使用了findandparallel來達到這個效果,但是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在由paralleland 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不鼓勵該選項。

引用自:https://unix.stackexchange.com/questions/85859