Bash

如何在不拆分輸出的情況下將腳本的輸出傳遞給 ls 之類的命令?

  • February 28, 2013

假設我有一個這樣的腳本:

#!/bin/bash
printf '%q\n' "b c"

執行腳本列印:

b\ c

在命令行上。

現在,在一個包含名為的文件的目錄中,b c我想將腳本的輸出傳遞給如下命令ls

$ ls $(./myscript)

這裡的問題b c是拆分為b\and c,即兩個參數,ls當然找不到它們。有什麼辦法可以規避這種情況嗎?我認為轉義輸出中的空間就足夠了。

使用引號:

$ ls "$(./myscript)"

命令替換

如果您需要將命令的輸出作為參數傳遞給另一個命令,請使用命令替換。與變數替換發生的情況類似,命令替換的結果會經歷分詞(在每個字元處拆分成單獨的詞,$IFS預設為空格)和萬用字元擴展(文件名的萬用字元)。因此,除非您希望進行拆分和通配,否則請始終在命令替換周圍使用雙引號。

ls -- "$(./myscript)"

--告訴ls停止處理選項,如果腳本列印的文件名以-.

您必須列印文字文件名。不要在腳本中添加額外的引用。

實際上存在一個參數被破壞的極端情況:命令替換從命令輸出中刪除任何最後的換行符。所以無論輸出是foo↲barorfoo↲bar↲還是foo↲bar↲↲↲(我用它來表示換行符),ls命令的參數都是foo↲bar. 這在實踐中幾乎不會發生,因為儘管文件名中允許使用換行符,但沒有人使用它們。儘管如此,這可能是一個安全問題,因為試圖攻擊您的系統的人可能會在文件名中添加換行符。

要處理最終的換行符,請安排命令輸出一個額外的非換行符,並將其從命令替換的結果中刪除。

output=$(./myscript; echo a)
output="${output%a}"
ls -- "$output"

將多個文件名傳遞給命令

不能出現在文件名或命令行參數中的一個字元是空字節。輸出多個文件名或其他要傳遞給命令的參數的安全方法是將它們用空字節分隔並呼叫xargs -0. 這適用於 Linux、*BSD 和 OSX,但它是其他 unix 變體可能缺乏的 POSIX 擴展。如果生成的命令行太長,xargs 會將其拆分並多次呼叫該命令。

… | xargs -0 ls

沒有-0,xargs期望輸入格式沒有其他常用命令產生。如果輸入不包含空格或任何\"'.

引用輸入的一種方法xargs是在至少以下字元之前放置一個反斜杠:換行符、製表符、空格和\"'.

for x in …; do
 printf '%s\n' "$x" | sed -e 's/[  '\''\"]/\\&/g' -e 's/$/\\$/' -e '$ s/\\$//'
done | xargs ls

在 sed 命令的括號內放置一個空格和一個製表符,而不是兩個空格字元。

關於不受保護的替換和引用的進一步說明

在未受保護的變數或命令替換中,對於發生通配的每個單詞,\[*?擴展四個字元。但是,只有字元[*? 會觸發萬用字元:沒有其他萬用字元的反斜杠保持不變。因此,如果目前目錄包含三個名為foogoo和的文件bar,則:

  • ls $(echo '?oo bar')``ls使用參數呼叫foogoo並且bar
  • ls $(echo '?\oo b\ar')``ls使用參數呼叫foogoo並且b\ar

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