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

Dea*_*nny 4 bash shell-script command-substitution subshell variable

我写了一个简单的脚本

 #!/bin/bash -x
 selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`
 echo $ts
Run Code Online (Sandbox Code Playgroud)

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

selentry=`ls -l / | sort`
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 5

在:

selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`
Run Code Online (Sandbox Code Playgroud)

与更现代的相同:

selentry=$(ls -l / | sort ; ts=${PIPESTATUS[0]})
Run Code Online (Sandbox Code Playgroud)

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

当你这样做时:

var=$(cmd)
Run Code Online (Sandbox Code Playgroud)

但是 的退出状态cmd在 中可用$?$PIPESTATUS在以下情况下,这不会扩展到:

var=$(foo | bar)
Run Code Online (Sandbox Code Playgroud)

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

但是,在这里,如果您不关心sort(子shell)的退出状态,则可以执行以下操作:

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

在这里,您还可以执行以下操作:

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=$?
Run Code Online (Sandbox Code Playgroud)

甚至:

{
  selentry=$(sort)
  sort_status=$?
  wait "$!"
  ls_status=$?
} < <(ls -l /)
Run Code Online (Sandbox Code Playgroud)

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

var=${
  foo; c1=$?
  bar; c2=$?
}
Run Code Online (Sandbox Code Playgroud)

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

var=$(
  foo; echo "c1=$?" > "$tempfile"
  bar; echo "c2=$?" >> "$tempfile"
)
. "$tempfile"
Run Code Online (Sandbox Code Playgroud)

或者在这里:

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