bash 变量中的新行

bash 变量中的新行

我试图在 bash 变量中存储多行,但它似乎不起作用。

例如,如果我/bin每行列出一个文件并将其存储在 中$LS,然后我将其$LS作为 stdin 传递给wc,它总是返回 1:

$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1

如果我尝试输出到屏幕,我会得到各种结果:echo在一行上打印所有行,而printf仅打印第一行:

#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS

那么,一个 bash 变量可以包含多行吗?

答案1

你需要双引号它(并且你应该 双引号变量大多数情况下):

echo "$LS"

不要使用回声打印变量内容,使用改为 printf:

printf '%s\n' "$LS"

答案2

换行符在变量中。LS=$(ls -1)将变量设置LS为 的输出ls -1(顺便说一句,它产生与 相同的输出ls,除非输出转到终端),减去尾随换行符。

问题是当您打印该值时要删除换行符。在 shell 脚本中,$LS并不意味着“变量的值LS”,它的意思是“获取 的值LS,根据 并将其拆分为单词,IFS并将每个单词解释为 glob 模式”。要获取 的值LS,您需要编写"$LS",或者更一般地说,将其放在$LS双引号之间。

echo "$LS"打印 的值LS,但在某些解释反斜杠字符的 shell 中以及少数以 开头的值除外-

printf "$LS"打印 的值,LS只要它不包含任何百分比或反斜杠字符并且(对于大多数实现)不以 开头-

要准确打印 的值LS,请使用printf %s "$LS"。如果您想在末尾添加换行符,请使用printf '%s\n' "$LS".

请注意$(ls),通常不是当前目录中的文件列表。仅当您有足够驯服的文件名时,这才有效。要获取文件名列表(点文件除外),您需要使用通配符:*。结果是字符串列表,而不是字符串,因此不能将其分配给字符串变量;您可以files=(*)在支持它们的 shell(ksh93、bash、zsh)中使用数组变量。

有关更多信息,请参阅为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?

答案3

之前所提

printf '%s\n' "$LS"

是唯一正确的解决方案。

让我证明其他提出的解决方案都具有echoprintf,根本无法正常工作:

$ mkdir t
$ cd t
$ touch \\n
$ LS=$(ls -l)
$ echo "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf "$LS\n"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf '%s\n' "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ ls -l
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ rm \\n
$ cd ..
$ rmdir t
$

(也可以使用V=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"和 变化进行测试。)

尽管\n文件名可能不那么常见,但存储git diff到一个变量中,你遇到文字的机会就会\n大大增加。

相关内容