[英]shell scripting process substitution <() inside command substitution $()
我有一個 output 為 1 的命令,類似於:
cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l
我需要將命令 output 與 if 語句中的值進行比較:
if [ $(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) = "1" ]; then ...
我遇到的錯誤與語法有關:意外標記附近的語法錯誤('
在[
和之前]
之后留一個空格。 [
是一個類似於test
的實際命令。 您需要將命令與其參數分開。 ]
不是命令,但[
命令參數的語法規則也要求將其分開。
if [ $(cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l) = "1" ]; then ...
編輯:使用新版本的問題,加上您所做的評論,答案很簡單。 您的代碼(您問題的當前版本中的代碼)完全可以。 它在我所有使用 bash 的計算機上都能正常工作。 但它是bash。 不是噓。
如果您將它與 /bin/sh 一起使用(正如您在其中一條評論中所說的那樣),那么您得到的錯誤是
/bin/sh: 1: Syntax error: "(" unexpected
這里出乎意料的括號是<(...)
語法之一。 這是 bash 特定語法。 /bin/sh 不能使用 pip/進程替換。
了解 <(command) 語法是一種特殊的替換。 它在另一個進程中運行命令,output 重定向到 pipe,其文件名被替換為 <(command) 部分。 echo <(ls)
例如顯示類似/dev/fd/63
的內容,它是一個名為 pipe 的“文件”,其“內容”是ls
的結果(即使它不是文件,也沒有內容.但是讀/dev/fd/63就是讀ls的output。還是蠻有用的,即使大多數時候,你也不需要它。但它是最近的(好吧,也許一兩年。但是當我學習 sh/bash 時它不存在),而不是 /bin/sh 的一部分。
所以答案是:你需要 bash。 你不能在 /bin/sh 中這樣做
如果您想將 cmp 與兩個命令的 output 一起使用,並且您真的不能只使用#!/bin/bash
而不是#!/bin/sh
,更簡單(但效率較低)的解決方案是使用臨時文件首先存儲命令的結果(希望這些命令不會產生千兆字節的輸出),然后比較它們。
或者,您可以使用命名管道重現非常相似的行為。
#!/bin/sh
mknod /tmp/pipe1.$$ p
mknod /tmp/pipe2.$$ p
echo ABCDEF > /tmp/pipe1.$$ &
echo ABCxEF > /tmp/pite2.$$ &
if [ $(cmp -bl /tmp/pipe1.$$ /tmp/pite2.$$ | wc -l) = "1" ]; then
echo One and only one diff
fi
rm /tmp/pipe1.$$
rm /tmp/pipe2.$$
它的作用大致相同 The echo stuff > /tmp/pipe1.$$ &
用於echo stuff
進程(將 echo 替換為您想要的任何命令)。 Whouse output 被重定向到名為 pipe /tmp/pipe1.$$ 我們在第一行創建的。 (.$$ 后綴,只是為了確保沒有其他進程可以使用相同的 /tmp/pipe1 名稱,因為 $$ 是我們進程的 pid)然后你有一個非常經典的if [ $(cmp /tmp/pipe1.$$ /tmp/pipe2.$$ | wc -l) ]
其中, cmp 只是用兩個文件名調用,它們恰好是命名管道(畢竟與 <(...) 完全相同)
但同樣,只有當您有充分的理由想要一個純 sh(而不是 bash)解決方案時。 在這種情況下,您還應該編輯您的問題以刪除“bash”標簽。
================= 舊答案 ==========================
這對我來說似乎很令人費解。 例如,使用 cmp foo <(echo 0) 將 foo 的內容(foo 本身是 cmp 上的 wc -l 的結果)與 0 進行比較。但我想你已經明白了,你明白這是一個 Rube-Goldberg 裝置而不是“== 0”,並且您了解每個 <() 派生一個進程,並從該進程返回一個管道名稱(當您需要傳遞包含執行命令的結果)。
如果不是,你應該解釋你真正想要做什么,因為,即使用真正的命令替換 <(echo...) (我也推測這些只是例子),cmp 和 wc 的這幾個階段是不可能的是正確的方法。
話雖這么說,只需在 [ 和 ] 周圍添加一個空格,它就會完全按照您的意圖進行。 (編輯:正如其他人在更快的回復和評論中所說的那樣。我輸入的答案太長......我不會刪除這個答案,因為序言可能是相關的)
編輯:回復更多關於使用部分
==
僅在 linux 中有效,因為 wc output 是一串數字,僅此而已。 由於標題空格,它不在mac上。 所以1
與1
不同。[
而不是[[
, [
是和外部命令,而[[
是 bash 語法( [[
更好:沒有進程的分叉),在將參數傳遞給[
命令的過程中,空格1
會丟失所以,總的來說
if [[ $(cmp -bl <(echo string1) <(echo string2) | wc -l) -eq 1 ]]
then
echo one and only one difference
fi
應該管用。 同樣,不確定它是最快的,也不是最短的,也不是最優雅的解決方案。 但只要沒有人提供更好的...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.