任何人都可以解释此行为? 运行:
#!/bin/sh echo "hello world" | read var1 var2 echo $var1 echo $var2
结果没有任何输出,而:
#!/bin/sh echo "hello world" > test.file read var1 var2 < test.file echo $var1 echo $var2
产生预期的输出:
hello world
在第二个例子中,pipe道不应该在一步中做什么redirect到test.file? 我用同样的代码与破折号和bash炮弹,并从他们得到相同的行为。
最近添加到bash
是lastpipe
选项,该选项允许在作业控制被停用时,管道中的最后一个命令在当前shell中运行,而不是子shell。
#!/bin/bash set +m # Deactiveate job control shopt -s lastpipe echo "hello world" | read var1 var2 echo $var1 echo $var2
将确实输出
hello world
这已经被正确回答了,但是解决方案还没有被陈述。 使用ksh,而不是bash。 比较:
$ echo 'echo "hello world" | read var1 var2 echo $var1 echo $var2' | bash -s
至:
$ echo 'echo "hello world" | read var1 var2 echo $var1 echo $var2' | ksh -s hello world
ksh是一个优秀的编程外壳,因为这样的小细节。 (在我看来,bash是更好的交互式shell。)
#!/bin/sh echo "hello world" | read var1 var2 echo $var1 echo $var2
不会产生输出,因为管道在子shell中运行其每个组件。 子壳继承父壳体变量的副本 ,而不是共享它们。 尝试这个:
#!/bin/sh foo="contents of shell variable foo" echo $foo ( echo $foo foo="foo contents modified" echo $foo ) echo $foo
圆括号定义了一个在子shell中运行的代码区域,$ foo在内部被修改后保留了它的原始值。
现在试试这个:
#!/bin/sh foo="contents of shell variable foo" echo $foo { echo $foo foo="foo contents modified" echo $foo } echo $foo
大括号纯粹是为了分组,不会创建子shell,而在大括号内修改的$ foo是在它们外面修改的$ foo。
现在试试这个:
#!/bin/sh echo "hello world" | { read var1 var2 echo $var1 echo $var2 } echo $var1 echo $var2
在大括号内部,内置的读内容正确地创建$ var1和$ var2,你可以看到它们被回显。 在大括号之外,他们不再存在了。 所有大括号内的代码已经在子shell中运行, 因为它是管道的一个组件 。
你可以在花括号之间插入任意数量的代码,所以当你需要运行一个shell脚本来分析其他东西的输出时,你可以使用这种管道式的块结构。
read var1 var2 < <(echo "hello world")
好的,我明白了!
这是一个难以捉摸的错误,但是结果来自于shell处理管道的方式。 管道的每个元素都在一个单独的进程中运行。 当读命令设置var1和var2时,将它设置为它自己的子shell,而不是父shell。 所以当子shell退出时,var1和var2的值就会丢失。 但是,你可以尝试做
var1=$(echo "Hello") echo var1
这将返回预期的答案。 不幸的是,这只适用于单个变量,你不能一次设置很多。 为了一次设置多个变量,您必须读入一个变量并将其分成多个变量或使用如下所示:
set -- $(echo "Hello World") var1="$1" var2="$2" echo $var1 echo $var2
虽然我承认它不像使用管道那样优雅,但它的工作原理。 当然,你应该记住,读取是为了从文件读入变量,所以从标准输入读取应该有点困难。
我在这个问题上(使用Bash):
read var1 var2 <<< "hello world" echo $var1 $var2
这是因为管道版本正在创建一个子shell,它将变量读入本地空间,然后在子shell退出时被销毁。
执行这个命令
$ echo $$;cat | read a 10637
并使用pstree -p来查看正在运行的进程,您将看到一个额外的shell挂在主shell上。
| |-bash(10637)-+-bash(10786) | | `-cat(10785)
这个帖子已经得到了很好的回答,但是我想提供一个可能有用的替代版本。
为了从echo(或stdout)分配空间分隔值到shell变量,你可以考虑使用shell数组:
$ var=( $( echo 'hello world' ) ) $ echo ${var[0]} hello $ echo ${var[1]} world
在这个例子中,var是一个数组,内容可以使用$ {var [index]}构造来访问,其中index是数组索引(从0开始)。
这样,你可以有任意多的参数,你想分配给相关的数组索引。
尝试:
echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )
正如多人所说,问题在于var1和var2是在子shell环境中创建的,当子shell退出时会被销毁。 上面的内容避免了子shell的破坏,直到结果被echo'd。 另一个解决方案是
result=`echo "hello world"` read var1 var2 <<EOF $result EOF echo $var1 echo $var2