仅当命令没有失败时,我才想将a
命令结果的第一个字分配给我的变量。func <some_arg>
如果失败了,我需要记录下来。
到目前为止我所做的是:
func() {
if [[ $1 -eq 1 ]]
then
echo 'hello world'
return 0
fi
echo 'Something wrong has happened!' >> path/to/dev.log
return 2
}
a=$(func 1)
r=$?
if [[ $r -eq 0 ]]
then
a=$(awk '{ print $1 }' <<<"$a")
fi
这当然有效,但我不喜欢将变量分配a
两次。
我试过这个:
a=$(func 2 | awk '{ print $1 }') || echo 'Something wrong has happened!' >> path/to/dev.log
但它不记录任何内容
有没有更好的办法?
答案1
您可以使用set -o pipefail
从管道的早期部分获取错误:
管道的返回状态是最后一个命令的退出状态,除非管道故障选项已启用。如果管道故障启用后,管道的返回状态是最后一个(最右边)以非零状态退出的命令的值,如果所有命令都成功退出,则返回零。
$ foo() { [[ "$1" = 1 ]] || return 1; echo "hello world"; }
$ a=$(set -o pipefail; foo 2 | awk '{print $1}' || echo "fail..." >&2)
fail...
但实际上,我不明白为什么分配两次会成为问题。本质上,如果命令成功,您只需修改获得的值,如果命令失败,则忽略它。
另外,您可以稍微压缩一下该逻辑:
if a=$(foo 1); then
a=${a%% *};
echo "first word of a is '$a'";
# do some work with $a...
else
echo "error..." >&2;
fi
印刷
first word of a is 'hello'
答案2
shell 有几种本地方法来解析字符串的第一个单词:
按后缀修剪 -
${a%% *}
分配给位置参数 -
set -- ${a}
结果将在$1
.您可以使用 来简化此操作set -- $(func 1)
。bash
(仅)划分为数组元素-a=( $(func 1) )
- 结果将在${a[0]}
.
答案3
a
您的代码的一个问题是,即使函数func
返回非零结果,它也会崩溃。
反而:
#!/bin/sh
func () {
if [ "$1" -eq 1 ]; then
echo 'some sort of logging stuff' >>logfile
return 1
fi
echo 'hello world'
}
a="a string"
if b=$( func 0 ); then
a=${b%% *}
fi
printf '1: a = "%s"\n' "$a"
a="a string"
if b=$( func 1 ); then
a=${b%% *}
fi
printf '2: a = "%s"\n' "$a"
运行这个会产生
1: a = "hello"
2: a = "a string"
正如您所看到的,在第二种情况下,a
保留了其价值。