不删除非尾随换行符
您正在寻找的换行符在那里,您只是看不到它们,因为您使用 echo 而不引用变量。
验证:
$ a=$( df -H )
$ echo $a
Filesystem Size Used Avail Use% Mounted on /dev/sda3 276G 50G 213G 19% / udev 2.1G 4.1k 2.1G 1% /dev tmpfs 832M 820k 832M 1% /run none 5.3M 0 5.3M 0% /run/lock none 2.1G 320k 2.1G 1% /run/shm
$ echo "$a"
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 276G 50G 213G 19% /
udev 2.1G 4.1k 2.1G 1% /dev
tmpfs 832M 820k 832M 1% /run
none 5.3M 0 5.3M 0% /run/lock
none 2.1G 320k 2.1G 1% /run/shm
$
尾随换行符被删除
正如 @user4815162342 正确指出的那样,虽然输出中的换行符没有被删除,但 尾随换行符 会通过命令替换被删除。请参阅下面的实验:
$ a=$'test\n\n'
$ echo "$a"
test
$ b=$(echo "$a")
$ echo "$b"
test
$
在大多数情况下,这无关紧要,因为echo 将添加已删除的换行符(除非使用-n 选项调用它),但在某些极端情况下,输出中有多个尾随换行符一个程序,并且由于某种原因它们很重要。
解决方法
1。添加虚拟字符
在这些情况下,如 @Scrutinizer 所述,您可以使用以下解决方法:
$ a=$(printf 'test\n\n'; printf x); a=${a%x}
$ echo "$a"
test
$
解释:字符x被添加到输出中(使用printf x),在换行符之后。由于换行符不再尾随,因此它们不会被命令替换删除。下一步是删除我们添加的x,使用${a%x} 中的% 运算符。现在我们有了原始输出,所有换行符都存在!!!
2。使用进程替换读取
我们可以代替使用命令替换将程序的输出分配给变量,而是使用process substitution 将程序的输出提供给read 内置命令(感谢@ormaaj)。进程替换保留所有换行符。将输出读取到变量有点棘手,但您可以这样做:
$ IFS= read -rd '' var < <( printf 'test\n\n' )
$ echo "$var"
test
$
解释:
- 我们将读取命令的internal field separator 设置为空,使用
IFS=。否则read 不会将整个输出分配给var,而只会分配给第一个标记。
- 我们使用选项
-rd '' 调用read。 r 用于防止反斜杠充当特殊字符,d '' 将分隔符设置为空,以便 read 读取整个输出,而不仅仅是第一行。
3。从管道中读取
我们可以代替使用命令或进程替换将程序的输出分配给变量,而是将程序的输出通过管道传递给read 命令(归功于@ormaaj)。管道还保留所有换行符。但是请注意,这次我们使用the shopt builtin 设置lastpipe shell 可选行为。这是必需的,以便在当前 shell 环境中执行 read 命令。否则,该变量将在子 shell 中分配,并且无法从脚本的其余部分访问。
$ cat test.sh
#!/bin/bash
shopt -s lastpipe
printf "test\n\n" | IFS= read -rd '' var
echo "$var"
$ ./test.sh
test
$