击:为什么管道输入到"读"而读..."只有当送入&QUOT工程;构造? [英] Bash: Why piping input to "read" only works when fed into "while read ..." construct?

查看:218
本文介绍了击:为什么管道输入到"读"而读..."只有当送入&QUOT工程;构造?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直想读这样的投入环境变量,从程序的输出:

I've been trying to read input into environment variables from program output like this:

echo first second | read A B ; echo $A-$B 

和结果是:

-

A和B都总是空的。我读到的bash在子shell执行管道命令和基本preventing一个来自管道输入读取数据。但是,以下

Both A and B are always empty. I read about bash executing piped commands in sub-shell and that basically preventing one from piping input to read. However, the following:

echo first second | while read A B ; do echo $A-$B ; done

似乎工作,其结果是:

Seems to work, the result is:

first-second

有人能解释什么是这里的逻辑是什么?难道这里面的命令,而 ... 完成构造在同一外壳实际执行为回声,而不是在一个子shell?

Can someone please explain what is the logic here? Is it that the commands inside the while ... done construct are actually executed in the same shell as echo and not in a sub-shell?

推荐答案

庆典(和其他的外壳也),当你管什么 | 到另一个命令,你会隐含创建的的,一个子shell谁是本届会议的一个孩子,谁也不能影响当前会话的ENVIRON

How to do a loop against stdin and get result stored in a variable

Under bash (and other shell also), when you pipe something by using | to another command, you will implicitely create a fork, a subshell who's a child of current session and who can't affect current session's environ.

所以这个:

TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
  while read A B;do
      ((TOTAL+=A-B))
      printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
    done
echo final total: $TOTAL

不会给预期的结果:

won't give expected result:

  9 -   4 =    5 -> TOTAL=    5
  3 -   1 =    2 -> TOTAL=    7
 77 -   2 =   75 -> TOTAL=   82
 25 -  12 =   13 -> TOTAL=   95
226 - 664 = -438 -> TOTAL= -343
echo final total: $TOTAL
final total: 0

如果计算的 TOTAL 的could'nt在主脚本中重复使用。

Where computed TOTAL could'nt be reused in main script.

使用庆典进程替换在这里,文件的或的这里字符串的,你可以逆叉:

By using bash Process Substitution, Here Documents or Here Strings, you could inverse the fork:

read A B <<<"first second"
echo $A
first

echo $B
second

在这里的文档

while read A B;do
    echo $A-$B
    C=$A-$B
  done << eodoc
first second
third fourth
eodoc
first-second
third-fourth

在循环外部:

echo : $C
: third-fourth

在这里命令

tot=0
while read A B ;do
    echo $((A-B))
    ((tot+=A-B))
  done < <(
    printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664
)
5
2
75
13
-438

# and finally out of loop:
echo $tot
-343

管道连接到的命令列表

但只是针对工作的标准输入的,您可以创建一种脚本到的的:

Piping to a command list

But for working only against stdin, you may create a kind of script into the fork:

printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 | {
    while read A B;do
        ((TOTAL+=A-B));
        printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL;
    done
    echo "Out of the loop total:" $TOTAL
  }

会给:

  9 -   4 =    5 -> TOTAL=    5
  3 -   1 =    2 -> TOTAL=    7
 77 -   2 =   75 -> TOTAL=   82
 25 -  12 =   13 -> TOTAL=   95
226 - 664 = -438 -> TOTAL= -343
Out of the loop total: -343

请注意: $ TOTAL 无法在主脚本的(后右花括号} )。

Note: $TOTAL could not be used in main script (after right curly bracket } ).

由于@CharlesDuffy正确地指出的那样,是用来改变这种行为一个bash选项。但对于这一点,我们必须先停用 作业控制的:

As @CharlesDuffy correctly pointed out, there is a bash option used to change this behaviour. But for this, we have to first disable job control:

shopt -s lastpipe           # Set *lastpipe* option
set +m                      # Disabling job control
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
  while read A B;do
      ((TOTAL+=A-B))
      printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
    done

  9 -   4 =    5 -> TOTAL= -338
  3 -   1 =    2 -> TOTAL= -336
 77 -   2 =   75 -> TOTAL= -261
 25 -  12 =   13 -> TOTAL= -248
226 - 664 = -438 -> TOTAL= -686

echo final total: $TOTAL
-343

这将工作,但我(个人)不喜欢这个,因为这不是的标准的,并不会有助于使脚本的可读性。同时禁用作业控制看起来很贵访问此行为。

This will work, but I (personally) don't like this because this is not standard and won't help to make script readable. Also disabling job control seem expensive for accessing this behaviour.

注意: 作业控制的默认情况下,只有在的交互的会话启用。因此,组+ M 不要求在正常的脚本。

Note: Job control is enabled by default only in interactive sessions. So set +m is not required in normal scripts.

所以忘了在脚本会产生,如果运行控制台或在脚本中运行不同的行为设定+ M 。这会不会让这个容易理解和调试...

So forgotten set +m in a script would create different behaviours if run in a console or if run in a script. This will not going to make this easy to understand or to debug...

这篇关于击:为什么管道输入到&QUOT;读&QUOT;而读...&QUOT;只有当送入&QUOT工程;构造?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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