了解使用 {} 和多個 `\ls` 的複雜命令替換

了解使用 {} 和多個 `\ls` 的複雜命令替換

我試圖從 shell 腳本中理解這一行。我知道這$(..)意味著運行並將其輸出插入到語句中..找到的位置。$()但是這些括號之間發生了什麼事?這是做什麼的\ls\這是\\兩條線的分割嗎?\ls和普通的一樣嗎ls

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

答案1

3 個命令的輸出ls將傳遞到將paste它們合併到值中的命令:

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

筆記:變數$VOLTDB_VOLTDB$VOLTDB_LIB將被擴展,並且每個ls命令可能有多個值,而不僅僅是一個檔案。看到*那裡了嗎?這是一個通配符,可擴展為左側 (voltdb-) 和右側 (.jar) 之間的任何內容。

這些將匹配:

voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar

然後所有內容都包含在變數中APPCLASSPATH

APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.

貼上命令

seq下面是我使用指令產生數字序列 1-10 的範例。

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

您可以看到該paste指令正在合併輸出並以冒號 ( :) 分隔。

您也可以像這樣模仿範例命令:

$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3

筆記:to -the Past 命令告訴它從 STDIN 獲取輸入並列印輸入的每個參數,以:.

透過不同的開關,paste還可以根據-資料後面的數量將資料分成組。

貼上範例

這是一個帶有 2-的範例。

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

這是 3-的。

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

所以它告訴每行應該要列印paste多少個參數。paste但不要混淆,您正在處理的示例只是從 STDIN 獲取輸入,用空格分隔每個參數,然後打印它,後跟:.當給出多個-' 時,您是在告訴paste您接受參數,一次 2 個,一次 3 個,等等。

一次 2 個參數,用:' 分隔:

$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10

$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::

順便說一句,如果您包含-s開關,您將告訴您paste按順序(串行)獲取參數。觀察當您在上面的範例之一中使用它時會發生什麼。

一次 2 個:

$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10

一次 3 個:

$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10

答案2

$(command)執行命令並替換其輸出。

{ list; }是一個群組命令,在目前shell環境中執行多個命令。它與 類似(list),但它不會建立子 shell。

\command用於忽略命令的別名,這可能會大大改變命令的預期行為。

行尾\僅表示該行繼續,因此 shell 會將下一行視為目前行的一部分。當從上下文(左括號或引號)中顯而易見時,通常沒有必要。

答案3

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

\ls與 類似ls,只不過 ifls是別名,反斜線可防止別名擴充。這保證了ls使用該命令,而不是使用可能添加不需要的輸出的別名,例如分類器後綴 ( -F)。

這些ls命令以現有檔案名稱作為參數調用,列出其參數,每行一個。此選項-1無效,因為 的輸出ls將發送到管道而不是終端。如果ls接收到的參數不是現有文件的名稱,它將在其標準輸出上不顯示任何內容,而是顯示錯誤。命令中的錯誤ls將被重定向到任何地方2> /dev/null。有兩個原因ls可能會收到不是檔案的參數:如果其中一個變數沒有引用現有的可讀目錄,或沒有與通配符模式相符的檔案。無論哪種情況,模式都會以未擴展的方式傳遞到ls.

行末端的反斜線導致 shell 忽略後面的換行符號。它們在這裡都沒有用,因為在使用它們的每個點上,shell 都需要一個可選的換行符號。

大括號 { … } 將指令分組。複合命令{ \ls …; \ls …; \ls … ; }透過管道傳輸到paste並將其錯誤重定向到/dev/null.

paste命令將所有輸入行連接在一起:。它相當於,tr '\n' :只是它沒有:在末尾添加 a。

指令替換$(…)導致 的輸出paste被插值到變APPCLASSPATH數值之後,CLASSPATH並用冒號分隔兩個部分。

這是一個簡化版本。這與原始版本略有不同,因為如果沒有通配符模式匹配任何內容,APPCLASSPATH則將等於CLASSPATH沒有額外的尾隨冒號(這可能是可取的)。

APPCLASSPATH=$CLASSPATH:$(
  \ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
  tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}

相關內容