linux脚本读取奇数,关于linux:Shell脚本输入重定向奇数

谁能解释这种行为?

正在运行:

#!/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

管道不应该一步一步地执行第二个示例中对test.file的重定向吗? 我对破折号和bash壳都尝试了相同的代码,并且两者的行为相同。

bash选项是最近添加到bash的选项,当停用作业控制时,该选项允许管道中的最后一条命令在当前外壳程序(而不是子外壳程序)中运行。

#!/bin/bash

set +m      # Deactiveate job control

shopt -s lastpipe

echo"hello world" | read var1 var2

echo $var1

echo $var2

确实会输出

hello

world

#!/bin/sh

echo"hello world" | read var1 var2

echo $var1

echo $var2

因为管道在子外壳中运行它们的每个组件,所以不会产生任何输出。子外壳继承父外壳变量的副本,而不是共享它们。尝试这个:

#!/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

花括号仅用于分组,不创建子外壳,花括号内部修改的$ foo与花括号外部修改的$ foo相同。

现在尝试这个:

#!/bin/sh

echo"hello world" | {

read var1 var2

echo $var1

echo $var2

}

echo $var1

echo $var2

在花括号内,内置的read会正确创建$ var1和$ var2,您可以看到它们得到了回应。在大括号之外,它们不再存在。花括号中的所有代码都在子shell中运行,因为它是管道的一个组成部分。

您可以在花括号之间放置任意数量的代码,因此,每当需要运行用于解析其他内容的shell脚本块时,便可以使用这种"管道成块"构造。

+1干净的示例-精美易读的代码

已经正确回答了此问题,但尚未提出解决方案。使用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是更好的交互式外壳。)

read var1 var2 <

我对这个问题的看法(使用Bash):

read var1 var2 <<

echo $var1 $var2

该职位已得到适当的答复,但我想提供一种可能有用的替代衬垫。

要将回声(或标准输出)中的空格分隔值分配给外壳变量,可以考虑使用外壳数组:

$ var=( $( echo 'hello world' ) )

$ echo ${var[0]}

hello

$ echo ${var[1]}

world

在此示例中,var是一个数组,可以使用构造$ {var [index]}访问内容,其中index是数组索引(从0开始)。

这样,您可以将任意数量的参数分配给相关的数组索引。

好的解决方案。 它在bash中效果很好,但在dash shell中不起作用。

好吧,我知道了!

这是一个很难捕获的错误,但是是由外壳处理管道的方式导致的。管道的每个元素都在单独的过程中运行。当read命令设置var1和var2时,将它们设置为自己的子shell,而不是父shell。因此,当子外壳程序退出时,var1和var2的值将丢失。您可以尝试做

var1=$(echo"Hello")

echo var1

返回预期的答案。不幸的是,这仅适用于单个变量,您一次不能设置多个。为了一次设置多个变量,您必须读入一个变量并将其切成多个变量,或者使用类似以下的方法:

set -- $(echo"Hello World")

var1="$1" var2="$2"

echo $var1

echo $var2

虽然我承认它不如使用管道优雅,但它可以工作。当然,您应该记住,读取是要从文件读取为变量,因此使其从标准输入中读取会有点困难。

这取决于外壳的选择。 Ksh93旨在限制过程开销。 它还在调用外壳程序内部运行管道的最后一个元素,从而保留状态。

Bash 4.2引入了执行相同操作的选项。 关闭作业控制(set +m)并设置lastpipe选项(shopt -s lastpipe)。

虐待调查。 谢谢!

这是因为管道版本正在创建一个子外壳,该子外壳将变量读入其本地空间,然后在子外壳退出时销毁该变量。

执行此命令

$ echo $$;cat | read a

10637

并使用pstree -p查看正在运行的进程,您将看到一个额外的shell挂在主shell上。

|                       |-bash(10637)-+-bash(10786)

|                       |             `-cat(10785)

尝试:

echo"hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )

正如多人所言,问题是var1和var2是在子外壳程序环境中创建的,而该子外壳程序退出后会被破坏。上面的代码避免了破坏子外壳,直到结果被回显为止。另一个解决方案是:

result=`echo"hello world"`

read var1 var2 <

$result

EOF

echo $var1

echo $var2

您可以通过内联$result来缩短此时间(但是很难在StackOverflow注释中显示)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值