Bash 腳本和引用

Bash 腳本和引用

我正在閱讀幾本有關 bash 腳本編寫的書籍,並努力理解正確的引用和IFS.也許有人可以幫我舉一個涉及引號的檔案名稱的小例子。從命令列執行此操作,可以正確列印檔案名,即使它們包含空格:

set - *
for i in "$@"; do echo $i; done

這不起作用,因為它會在空格處中斷:

set - `find . -name "*"`
for i in "$@"; do echo $i; done

也不:

IFS=$'\0' set - `find . -name "*" -print0`
for i in "$@"; do echo $i; done

IFS=$'\n'使用和 的組合也不行-print。為什麼這些都失敗了?

以下內容也會失敗,但在這種情況下會出錯(「bash:意外標記『do』附近的語法錯誤」)。為什麼?

IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done 

但這是有效的(注意“;”):

IFS=$'\n'; for i in `find . -name "*" -type f`; do echo $i; done 

這會失敗,因為檔案名稱根本沒有分割(for僅循環一次):

IFS=''; for i in `find . -name "*" -type f -print0`; do echo -e "$i\n"; done

那麼問題來了,為什麼第一個和第三個會失敗呢?

最後,我的信念是否正確,即設定時IFS''與 相同$'\0'? (我在前面的例子中嘗試了兩者。)如果是這樣,為什麼我顯然需要$'\n'而不只是\n

*Ubuntu Gnome 16.04 中的 Bash 版本為 4.3.42(1)。

答案1

我在調試 bash 命令時學到了兩件事:一)如果它沒有像您想像的那樣工作,請 echo/printf 輸出命令以確保它們以您認為應該的方式顯示。二)手動執行命令中的命令以查看它們是否正常運行(除非這些命令具有潛在的破壞性,例如:rm、dd、chmod 777 等)。

您究竟想如何實現或實現什麼目標?我的似乎可以逐字使用該命令,因此您需要解釋您想要它做什麼。檔案名稱中是否有空格導致指令出現問題?只要您刪除 IFS 變數中的空格,它可能會按照您想要的方式運作:IFS=$'\n\t'。該-print0選項基本上刪除了所有行分隔符,因此您想要從這些命令中獲得的所有內容根本沒有分隔符,除非檔案名稱中包含空格。對於你的第二組問題:

IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done 

該命令無法正常運行,因為 bash 是這樣讀取它的:

IFS=$'\n' for i in `find . -name "*" -type f`
do echo $i
done

第一行將 IFS 設為:$'\n' for i in。之後,下一行讀取為:do echo $i,這不起作用,因為該do命令需要某種循環作為前面的命令。下一個之所以有效,是因為分號告訴 bash 指令已到達結尾,因此:

IFS=$'\n'
for i in `find . -name "*" -type f`
do echo $i
done 

最後,我認為在設定 IFS 時,'' 與 $'\0' 相同,我的信念是否正確? (我在前面的示例中嘗試了兩者。)如果是這樣,為什麼我顯然需要 $'\n' 而不僅僅是 \n?

是的,第一部分,'''\0'都被認為是NULL,所以它們基本上是相同的。這是由於 bash 解釋$''為 ANSI C 字串。並且您需要在 \n 兩邊加引號,以使 bash 將其解釋為 C 字串,以便將換行符號放置在 IFS 中。
您可以閱讀有關這些的更多信息這裡

相關內容