访问命令替换中设置的变量

访问命令替换中设置的变量

我写了一个简单的脚本

 #!/bin/bash -x
 selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`
 echo $ts

但 $ts 什么也没显示。如何显示 $ts 变量,或者如何从变量中的命令获取退出状态代码?

selentry=`ls -l / | sort`

答案1

在:

selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`

与更现代的相同:

selentry=$(ls -l / | sort ; ts=${PIPESTATUS[0]})

中的代码在子 shell 环境中运行(在和 shell 以外的$(...)情况下,它甚至在不同的 shell 进程中运行)。因此,对该子 shell 中的变量进行的任何修改都不会影响父 shell。bashksh93

当你这样做时:

var=$(cmd)

然而 的退出状态cmd在 中可用$?。这并不适用于$PIPESTATUS以下情况:

var=$(foo | bar)

仅包含一个值(子shell的退出代码,这里将是退出状态bar(除非该选项打开,在这种情况下,如果它非零,则pipefail可能是退出状态)。数组所在的位置更糟不受赋值命令影响。foozsh$pipestatus

不过,在这里,如果您不关心sort(子 shell 的)退出状态,您可以这样做:

selentry=$(ls -l / | sort; exit "${PIPESTATUS[0]}")
ts=$?

在这里,你还可以这样做:

exec 3< <(ls -l /) # here ls is started as an asynchronous command
ls_pid=$!
selentry=$(sort <&3)
sort_status=$?
wait "$ls_pid"
exec 3<&- # close that fd 3
ls_status=$?

甚至:

{
  selentry=$(sort)
  sort_status=$?
  wait "$!"
  ls_status=$?
} < <(ls -l /)

关于让变量赋值在命令替换中继续存在的更普遍的问题,在 中ksh93,您可以使用${ cmd;}命令替换的形式(但ksh93不支持$PIPESTATUS/ $pipestatus)。

var=${
  foo; c1=$?
  bar; c2=$?
}

在其他类似 Bourne 的 shell 中没有类似的功能,您需要通过其他方式(例如临时文件)传递数据:

var=$(
  foo; echo "c1=$?" > "$tempfile"
  bar; echo "c2=$?" >> "$tempfile"
)
. "$tempfile"

或者在这里:

selentry=$(
  ls -l / | sort
  typeset -p PIPESTATUS | sed '1s/PIPESTATUS/my_&/' > "$tempfile"
}
. "$tempfile"
ls_status=${my_PIPESTATUS[0]}

相关内容