printf 只列印一行
我正在嘗試獲取
env
shell 變數中的輸出並列印它。#!/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
,printf
將foo
視為它的格式字元串和bar
它應該用它格式化的變數。由於沒有%s
或等價於bar
,bar
被忽略並foo
單獨列印:$ printf $var + printf foo bar foo
那就是你跑的時候發生的事情
printf $ENV_BEFORE
。因為變數沒有被引用,split glob 有效地用空格替換了換行符,並且printf
只列印了它看到的第一個“單詞”。要正確執行此操作,請使用格式字元串,並始終引用您的變數:
printf '%s\n' "$ENV_BEFORE"