Bash

printf 只列印一行

  • March 17, 2016

我正在嘗試獲取envshell 變數中的輸出並列印它。

#!/bin/sh
ENV_BEFORE=$(env)
printf $ENV_BEFORE

結果,env輸出中的單個變數被列印出來。

使用echo而不是printf列印所有輸出時,但沒有換行符。

我在這裡想念什麼?

問題是你沒有引用$ENV變數。如中所述man bash

用雙引號括起來的字元會保留引號內所有字元的字面值,除了 $ , , \, and, when history expansion is enabled, !. The characters $ 和 在雙引號中保留其特殊含義。 反斜杠僅在後跟以下字元之一時才保留其特殊含義:$、`、"、\ 或

因此,用雙引號將序列括起來可以\n保留其含義。這就是為什麼,當不引用時,\n它只是一個正常的n

$ printf \n
n$

同時,引用時:

$ printf "\n"

$

bash 中未加引號的變數呼叫 split+glob 運算符。這意味著變數在空格(或任何$IFS已設置的特殊變數)上拆分,並且每個結果單詞都用作一個 glob(它將擴展以匹配任何匹配的文件名)。您的問題在於其中的“拆分”部分。

為了說明,讓我們採用一個更簡單的多行變數:

$ var=$(printf "foo\nbar\n")

現在,使用 shell 的set -x調試功能,您可以準確地看到發生了什麼:

$ echo $var
+ echo foo bar
foo bar

$ echo "$var"
+ echo 'foo
bar'
foo
bar

正如您在上面看到的,echo $var(未加引號的)主題$var是 split+glob,因此它會產生兩個單獨的字元串,foo並且bar. 換行符被 split+glob 吃掉了。當變數被引用時,它沒有受到 split+glob 的影響,換行符被保留,並且因為它被引用,所以也被正確解釋並列印出來。

下一個問題就是printf不喜歡echo。它不只是列印你給它的任何東西,它需要一個格式字元串。例如printf "color:%s" "green"將列印color:green,因為%s將替換為green.

它還會忽略任何不適合其給出的格式字元串的輸入。因此,如果您執行printf foo bar,printffoo視為它的格式字元串和bar它應該用它格式化的變數。由於沒有%s或等價於bar,bar被忽略並foo單獨列印:

$ printf $var
+ printf foo bar
foo

那就是你跑的時候發生的事情printf $ENV_BEFORE。因為變數沒有被引用,split glob 有效地用空格替換了換行符,並且printf只列印了它看到的第一個“單詞”。

要正確執行此操作,請使用格式字元串,並始終引用您的變數:

printf '%s\n' "$ENV_BEFORE"

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