我在 debian 7 上有以下 shell 脚本:
#!/bin/sh
case "$IFACE" in
lo)
# The loopback interface does not count.
# only run when some other interface comes up
exit 0
;;
*)
;;
esac
(
flock -e 200
FLAGFILE=/var/run/cyvo-auto-started
if [ -e $FLAGFILE ]; then
exit 0
else
touch $FLAGFILE
fi
# Launch CyVo without the lock and as cyvo user
flock -u 200
sudo -u cyvo /usr/local/bin/cyvo-launch.sh
) 200>/var/lock/cyvo-autostart-lock # word unexpected here? (line 29)
它给我带来的错误是:
./cyvo: 29: ./cyvo: Syntax error: word unexpected
这对我来说真的很困惑,因为这是建议的语法群命令。它将传递文件描述符 200/var/lock/cyvo-autostart-lock
指向()
.
我究竟做错了什么?
答案1
您可以在 shell 脚本中移植使用的唯一文件描述符编号是 0 到 9(即单个数字)。引用POSIX:
打开的文件由从零开始的十进制数字表示。最大可能值是实现定义的;但是,所有实现都应至少支持 0 到 9(含)以供应用程序使用。这些数字称为“文件描述符”。 (…) 重定向运算符前面可以有一位或多位数字(不允许插入 <空白> 字符)来指定文件描述符编号。
这语法很明显,重定向运算符之前可以有多个数字。然而,大多数 shell 仅将运算符前面的数字解析为文件描述符(如果它由单个数字组成)。例如,根据 POSIX 规范,echo 10>a
应该将文件描述符 10 重定向到a
并创建一个空文件,或者因为 shell 不支持 10 作为文件描述符编号而出错。错误也可能是由于文件描述符数量超过了进程打开文件数量的限制。
但实际上大多数 shell 都会将其解析为echo 10 >a
,即 write 10
in a
。甚至 ATT ksh93 和 posh 也不合规,dash、mksh 和 zsh 也是如此:
$ ksh -c 'echo 10>a; wc -c a'
3 a
$ posh -c 'echo 10>a; wc -c a'
3 a
在 Linux 上,我只能找到符合 POSIX 标准的 bash、yash 和 BusyBox 的 ash。
$ bash -c 'echo 10>a; wc -c a'
0 a
类似地,(…) 200>somefile
应该被解析为重定向,并且可能会也可能不会工作,具体取决于 shell 是否支持这么高的文件描述符。但大多数 shell 会报告语法错误,因为它们不会将该200
部分解析为文件描述符编号,而是解析为普通标记。
在相关说明中,echo 01>&1
应该打印一个空行,因为01
应该被解析为文件描述符编号,但同样只有 bash 和 BusyBox ash 能做到这一点。
因此,在实践中,您只能使用单位数文件描述符在 shell 脚本中。描述符0、1和2具有标准含义;描述符 3-9 可以自由使用。 Shell 不会将 fd 3–9 用于其内部目的。无论您选择什么文件描述符,当 shell 启动时文件描述符可能已经打开,但这并不重要:脚本中的任何文件描述符重新分配都保留在脚本中,不会影响脚本的父进程。
答案2
再想一想,也许比我原来的答案(我在下面复制的,因为这是最初接受的)更简单的方法是将文件描述符从200
<9.例如,5。因此,将200
脚本中的所有三个实例更改为5
:
#!/bin/sh
case "$IFACE" in
lo)
# The loopback interface does not count.
# only run when some other interface comes up
exit 0
;;
*)
;;
esac
(
flock -e 5
FLAGFILE=/var/run/cyvo-auto-started
if [ -e $FLAGFILE ]; then
exit 0
else
touch $FLAGFILE
fi
# Launch CyVo without the lock and as cyvo user
flock -u 5
sudo -u cyvo /usr/local/bin/cyvo-launch.sh
) 5>/var/lock/cyvo-autostart-lock
原答案:
要么是因为sh
无法按照 @GlennJackman 建议处理 >9 的文件描述符,要么是由于其他一些特殊性,您的脚本无法使用sh
(基于dash
Debian 的发行版)。我尝试过bash
,效果很好,所以只需使用bash
即可。将第一行更改为
#!/bin/sh
到
#!/bin/bash
然后脚本应该按预期工作。