考虑这个脚本:
#!/bin/sh
foo=1
if [[ ! -z $foo ]]; then
echo abc
fi
Run Code Online (Sandbox Code Playgroud)
它使用 Bash 语法 [[ ... ]] 当我在 Ubuntu (dash) 上使用默认 shell 运行它时,它不起作用(如预期)。但是,它的返回码仍然为零。
$ ./tmp.sh
./tmp.sh: 4: ./tmp.sh: [[: not found
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)
如果我不能依赖退出代码,如何在脚本中检测这种错误?
在 Bash 中,您可以重定向当前正在运行的脚本的所有未来stdout 输出。例如使用这个脚本,
exec > >(logger -t my-awesome-script)
echo 1
echo 2
echo 3
Run Code Online (Sandbox Code Playgroud)
这将在系统日志中结束:
Oct 26 01:03:16 mybox my-awesome-script[72754]: 1
Oct 26 01:03:16 mybox my-awesome-script[72754]: 2
Oct 26 01:03:16 mybox my-awesome-script[72754]: 3
Run Code Online (Sandbox Code Playgroud)
但这是 Bash 特定的,带有重定向的裸 exec 在 Dash 中似乎不起作用。
Syntax error: redirection unexpected
Run Code Online (Sandbox Code Playgroud)
我怎样才能让它在 Dash 中工作,或者可能在两个 shell 中工作?
这是一个简单的脚本,它在当前目录中设置一个临时目录,并在退出时设置一个陷阱以将其删除。
#filename: script
set -x
trap 'rm -rf "$d"' exit
d=`TMPDIR=$PWD mktemp -d`
"$@"
Run Code Online (Sandbox Code Playgroud)
如果我执行ksh script sleep 100或bash script sleep 100中断它C-C,则执行陷阱并删除目录。它不适用于dash. 为什么?这是错误还是预期行为?
我写了一个脚本,它在运行时切换用户,并使用文件重定向到标准输入来执行它。所以user-switch.sh是......
#!/bin/bash
whoami
sudo su -l root
whoami
Run Code Online (Sandbox Code Playgroud)
并运行它bash给了我我期望的行为
$ bash < user-switch.sh
vagrant
root
Run Code Online (Sandbox Code Playgroud)
但是,如果我用 运行脚本sh,我会得到不同的输出
$ sh < user-switch.sh
vagrant
vagrant
Run Code Online (Sandbox Code Playgroud)
为什么bash < user-switch.sh给出的输出与sh < user-switch.sh?
我的dash脚本采用 形式的参数hostname:port,即:
myhost:1234
Run Code Online (Sandbox Code Playgroud)
而端口是可选的,即:
myhost
Run Code Online (Sandbox Code Playgroud)
我需要将主机和端口读入单独的变量。在第一种情况下,我可以这样做:
HOST=${1%%:*}
PORT=${1##*:}
Run Code Online (Sandbox Code Playgroud)
但这在第二种情况下不起作用,当端口被省略时;echo ${1##*:}只返回主机名,而不是空字符串。
在 Bash 中,我可以这样做:
IFS=: read A B <<< asdf:111
Run Code Online (Sandbox Code Playgroud)
但这在dash.
能否在拆分字符串:在仪表板,而无需调用外部程序(awk,tr,等)?
我知道以前对此的报道很少,但这些答案要么缺乏解释,要么不适用。
基本上在某些时候,我的脚本需要检查是否指定了文件,如果是,则稍后将用作输入。
[ -f "$1" ] && TINPUT="$1"
Run Code Online (Sandbox Code Playgroud)
足够简单......现在如果找不到文件或未指定文件,我TINPUT="-"会告诉后面的命令读取标准输入。
这是我的问题......如果脚本在没有管道或没有指定文件的情况下运行,我如何让脚本因错误而死?
我正在使用 dash,Debian POSIX 兼容 shell,所以我不能使用 Bashisms。我也更喜欢使用列表,ifs但大多数ifs都可以写在列表中。
跑步
bash -c 'bash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;'
Run Code Online (Sandbox Code Playgroud)
结果test1被打印到控制台并echo $?打印1在我的理解中是正确的,因为命令应该返回内部[b/d]ash -c返回的内容,而
dash -c 'dash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;'
Run Code Online (Sandbox Code Playgroud)
导致相同的输出,但0根据返回echo $?。
我想了解这种差异,以拓宽我对 shell 和可移植 shell 编程的理解。
我在 Ubuntu 17.10 (Artful Aardvark) 上使用bash4.4.12 和dash0.5.8-2.3ubuntu1。
我知道有些 shell 接受这种测试:
t() { [[ $var == *$'\n'* ]] && res=yes || res=no
printf '%s ' "$res";
}
var='ab
cd'
t
var='abcd'
t
echo
Run Code Online (Sandbox Code Playgroud)
执行时:
$ bash ./script
yes no
Run Code Online (Sandbox Code Playgroud)
什么是 POSIX(破折号)工作等效项
以下是可靠的测试方法吗?
nl='
'
t() { case "$var" in
*$nl* ) res=yes ;;
* ) res=no ;;
esac
printf '%s ' "$res"
}
var='ab
cd'
t
var='abcd'
t
echo
Run Code Online (Sandbox Code Playgroud)我在 AU 上发布了一个问题的答案,我发现参数扩展 on$@不适用于shshell:
<infile xargs -d'\n' sh -c 'echo "${@%%/*}"' _
Run Code Online (Sandbox Code Playgroud)
但它在bash. 这是shshell 的预期行为,我如何在那里执行扩展?
此外,我知道通过-n1选项xargs我一次只能将一行传递给命令,但我对是否sh可以扩展感兴趣$@:
<infile xargs -d'\n' -n1 sh -c 'echo "${0%%/*}"'
Run Code Online (Sandbox Code Playgroud)
infile 包含:
A1 /B1/C1
A 2/B2/C2
A3/B3/C3
Run Code Online (Sandbox Code Playgroud) 使用 Bash 和 Dash,您可以仅使用 shell 检查空目录(忽略点文件以保持简单):
set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi
Run Code Online (Sandbox Code Playgroud)
但是我最近了解到 Zsh 在这种情况下失败了:
% set *
zsh: no matches found: *
% echo "$? $#"
1 0
Run Code Online (Sandbox Code Playgroud)
所以不仅set命令失败,而且它甚至没有设置$@. 我想我可以测试 if $#is 0,但似乎 Zsh 甚至停止执行:
% { set *; echo 2; }
zsh: no matches found: *
Run Code Online (Sandbox Code Playgroud)
与 Bash 和 Dash 比较:
$ { set *; echo 2; }
2
Run Code Online (Sandbox Code Playgroud)
这可以以在 bash、dash 和 zsh …
dash ×10
shell ×6
bash ×5
exit-status ×2
shell-script ×2
stdin ×2
string ×2
ksh ×1
newlines ×1
portability ×1
posix ×1
subshell ×1
trap ×1
wildcards ×1
zsh ×1