如何避免bash命令替换删除换行符?

时间:2013-03-03 09:37:56

标签: bash newline command-substitution

为了加速一些bash脚本执行,我想使用命令替换将命令的结果保存在变量中,但是命令替换用空格替换0x0A换行符。例如:

a=`df -H`

a=$( df -H )

当我想进一步处理$a时,换行符被空格替换,所有行现在都在一行上,这更难以grep:

echo $a

通过命令替换来避免换行字符的简单方法是什么?

3 个答案:

答案 0 :(得分:104)

不删除非尾随换行符

您要查找的换行符就在那里,您只是看不到它们,因为您在不引用变量的情况下使用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


$ 

<强> 说明:

  • 我们将read命令的internal field separator设置为null,IFS=。否则read不会将整个输出分配给var,而只会分配给第一个标记。
  • 我们使用选项-rd ''调用readr用于防止反斜杠充当特殊字符,并且d ''将分隔符设置为空,以便读取读取整个输出,而不是仅读取第一行。

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


$

答案 1 :(得分:1)

另一个“巧妙的窍门”是使用回车符,该字符防止换行符被剥离,但不向输出添加任何内容:

$ my_func_1 () {
>     echo "This newline is squashed"
> }
$ my_func_2 () {
>     echo "This newline is not squashed"
>     echo -n $'\r'
> }
$ echo -n "$(my_func_1)" && echo -n "$(my_func_2)" && echo done
This newline is squashedThis newline is not squashed
done
$

但是买家要当心:正如评论中所提到的那样,这对于直接进入终端的输出可能效果很好,但是如果将其传递给另一个过程,您可能会感到困惑,因为它可能不会期望很奇怪终止'\r'

答案 2 :(得分:0)

我试图绕过这个因为我正在使用bash来传输在F#脚本上运行解释器的结果。经过一些反复试验,结果证明了这个问题:

$ cat fsi.ch
#!/bin/bash
echo "$(fsharpi --quiet --exec --nologo $1)"

$ fsi.ch messages.fsx
Welcome to my program. Choose from the menu:
new | show | remove

假设您需要运行终端程序。 希望这会有所帮助。