如何避免 bash 命令替换以删除换行符? [英] How to avoid bash command substitution to remove the newline character?

查看:28
本文介绍了如何避免 bash 命令替换以删除换行符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

To speed up some bash script execution, I would like to keep the result of a command in a variable using command substitution, but the command substitution replaces the 0x0A newline character by a space. For example:

a=`df -H`

a=$( df -H )

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

When I want to process further $a, the newline characters are replaced by a space and all the lines are now on one line, which is much harder to grep:

echo $a

避免换行符被命令替换删除的简单技巧是什么?

What would be the easy tricks to avoid the newline character being removed by the command substitution?

推荐答案

不移除非尾随换行符

您正在寻找的换行符就在那里,您只是看不到它们,因为您使用了 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 正确指出的那样,虽然输出中的换行符没有被删除,尾随的换行符被命令替换删除了.请参阅下面的实验:

Trailing newlines are removed

As @user4815162342 correctly pointed out, although newlines within the output are not removed, trailing newlines are removed with command substitution. See experiment below:

$ a=$'test

'
$ echo "$a"
test


$ b=$(echo "$a")
$ echo "$b"
test
$

在大多数情况下这无关紧要,因为 echo 会添加已删除的换行符(除非使用 -n 选项调用),但也有一些边缘情况在程序的输出中有更多的尾随换行符,并且由于某种原因它们很重要.

In most cases this does not matter, because echo will add the removed newline (unless it is invoked with the -n option), but there are some edge cases where there are more that one trailing newlines in the output of a program, and they are significant for some reason.

在这些情况下,正如 @Scrutinizer 所述,您可以使用以下解决方法:

In these case, as @Scrutinizer mentioned, you can use the following workaround:

$ a=$(printf 'test

'; printf x); a=${a%x}
$ echo "$a"
test


$ 

说明: 字符 x 被添加到输出中(使用 printf x),在换行符之后.由于换行符不再尾随,它们不会被命令替换删除.下一步是删除我们添加的 x,使用 ${a%x} 中的 % 运算符.现在我们有了原始输出,所有换行符都存在!!!

Explanation: Character x is added to the output (using printf x), after the newlines. Since the newlines are not trailing any more, they are not removed by the command substitution. The next step is to remove the x we added, using the % operator in ${a%x}. Now we have the original output, with all newlines present!!!

我们可以使用 进程替换 将程序的输出提供给 read 内置命令(归功于 @ormaaj).进程替换保留所有换行符.将输出读取到变量有点棘手,但您可以这样做:

Instead of using command substitution to assign the output of a program to variable, we can instead use process substitution to feed the output of the program to the read built-in command (credit to @ormaaj). Process substitution preserves all newlines. Reading the output to a variable is a bit tricky, but you can do it like this:

$ IFS= read -rd '' var < <( printf 'test

' ) 
$ echo "$var"
test


$ 

解释:

  • 我们设置了内部字段分隔符读取命令为空,IFS=.否则 read 不会将整个输出分配给 var,而只会分配第一个标记.
  • 我们调用 read带有选项 -rd ''.r 用于防止反斜杠充当特殊字符,并使用 d '' 将分隔符设置为空,以便 read 读取整个输出,而不仅仅是第一行.
  • We set the internal field separator for the read command to null, with IFS=. Otherwise read would not assign the entire output to var, but only the first token.
  • We invoke read with options -rd ''. The r is for preventing the backslash to act as a special character, and with d '' set the delimiter to nothing, so that read reads the entire output, instead of just the first line.

我们可以代替使用命令或进程替换将程序的输出分配给变量,而是将程序的输出通过管道传递给 read 命令(归功于 @ormaaj).管道还保留所有换行符.但是请注意,这次我们使用 shopt 内置.这是必需的,以便在当前 shell 环境中执行 read 命令.否则,该变量将在子 shell 中分配,并且无法从脚本的其余部分访问.

Instead of using command or process substitution to assign the output of a program to variable, we can instead pipe the output of the program to the read command (credit to @ormaaj). Piping also preserves all newlines. Note however, that this time we set the lastpipe shell optional behavior, using the shopt builtin. This is required, so that the read command is executed in the current shell environment. Otherwise, the variable will be assigned in a subshell, and it will not be accessible from the rest of the script.

$ cat test.sh 
#!/bin/bash
shopt -s lastpipe
printf "test

" | IFS= read -rd '' var
echo "$var"
$ ./test.sh 
test


$

这篇关于如何避免 bash 命令替换以删除换行符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆