新行和 bash 变量

Put*_*nik 0 bash newlines variable

我有一个文本文件(或管道输出,在这里无关紧要)

memcached.uptime 1061374
memcached.curr_connections 480
memcached.cmd_get 478962548
memcached.cmd_set 17641364
memcached.cmd_flush 0
Run Code Online (Sandbox Code Playgroud)

如果我使用命令,cat test.txt | while read i; do echo $i; done它会产生非常预期的输出:

memcached.uptime 1061374
memcached.curr_connections 480
memcached.cmd_get 478962548
etc
Run Code Online (Sandbox Code Playgroud)

但是如果我循环使用,for i in $(cat test.txt); do echo $i; done我会看到不同的东西:

memcached.uptime
1061374
memcached.curr_connections
480
memcached.cmd_get
478962548
etc
Run Code Online (Sandbox Code Playgroud)

问题是:为什么???

Sté*_*las 5

在:

cat test.txt | while read i; do echo $i; done
Run Code Online (Sandbox Code Playgroud)

您设法在许多 shell 脚本编写不良做法中进行了练习:

虽然我可能应该首先提到为什么使用 shell 循环来处理被认为是不好的做法的文本?.

尝试例如输入如下:

-n
/*/*/*/../../../*/*/*
  foo\
bar
Run Code Online (Sandbox Code Playgroud)

如果您确实需要使用 shell 循环,那可能必须是这样的:

{
while IFS= read <&3 -r i; do
  printf '%s\n' "$i" || exit
done
[ -z "$i" ] || printf %s "$i" || exit
} 3< test.txt
Run Code Online (Sandbox Code Playgroud)

for i in $(cat test.txt); do echo $i; done
Run Code Online (Sandbox Code Playgroud)

这用另一种代替了不好的做法。在这里,您有充分的理由不加$(cat test.txt)引号:您想要 split+glob 运算符的拆分部分,但您忘记指定要拆分的内容并禁用 glob 部分。

IFS='
' # split on newline only. The default value of $IFS
  # contains space, tab and newline which explains why you see
  # one word per line
set -o noglob # disable glob
for i in $(cat test.txt); do
  printf '%s\n' "$i" || exit
done
Run Code Online (Sandbox Code Playgroud)

请注意,仍然会跳过空行,并且在开始循环之前读取文件内容并将其存储在内存中(多次)。