我试图在 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
答案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"
是唯一正确的解决方案。
让我证明其他提出的解决方案都具有echo
和printf
,根本无法正常工作:
$ 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
大大增加。