我有以下脚本:
#!/bin/bash
# initialisation of the script
mkdir -p test_dir
touch test_dir/test{1..15}
touch test_dir/test{a..e}
# enabling etended glob
shopt -s extglob
# we count the number of files which name is touchNUMBER
for f in test_dir/test+([0-9]); do ((count++)); done; echo $count
它工作正常并打印15
。
但是,当我尝试将此脚本连接到一行时,它会返回错误:
#!/bin/bash
mkdir -p test_dir
touch test_dir/test{1..15}
touch test_dir/test{a..e}
shopt -s extglob; for f in test_dir/test+([0-9]); do ((count++)); done; echo $count
输出:
./test.sh: line 7: syntax error near unexpected token `('
在确定此行语法的正确性之前,似乎bash
未评估shopt -s extglob
。
编辑:
有趣的是,用以下内容替换了被控制的行:
shopt -s extglob; sleep 10;for f in test_dir/test+([0-9]); do ((count++)); done; echo $count
立即显示相同的错误消息,从而确认在执行该行之前引发了错误消息。
为什么?有办法吗?
答案 0 :(得分:4)
bash
逐行处理脚本。在第一种情况下,shopt -s extglob
已在解析for
循环时执行。在错误的情况下,您有一行在解析后将被识别为由;
分隔的两个命令。但是,这意味着当shopt -x extglob
需要识别扩展模式bash
时,尚未执行+([0-9])
。
没有理由在脚本中将其作为单行代码。单行程序旨在减少频繁执行的交互式命令的输入;在脚本中没有必要这样做,其中可读性应该被优先考虑。
答案 1 :(得分:0)
Bash读取脚本或逐行输入。然后它使用元字符解析整行将其划分为标记(|
&
;
(
)
<
>
{{ 1}} space
tab
)而它也会识别引号和扩展。
并且,只有整行已被表征为每个部分开始执行。
在简单的情况下,每个命令都应放在各自独立的行中 这有效:
newline
虽然这不起作用:
$ shopt -u extglob
$ shopt -s extglob
$ echo "test_dir/test"+([0-9])
test_dir/test01 test_dir/test11 test_dir/test22
但这不是整个历史。如果我们设法使用引号或扩展来延迟评估,那么该行将起作用:
$ shopt -u extglob
$ shopt -s extglob ; echo "test_dir/test"+([0-9])
bash: syntax error near unexpected token `('
或者:
$ shopt -u extglob
$ shopt -s extglob ; echo $(echo "test_dir/test"+([0-9]))
test_dir/test01 test_dir/test11 test_dir/test22
原因是子shell $ shopt -u extglob
$ shopt -s extglob ; a=$(echo test_dir/test+([0-9])); echo "$a"
test_dir/test01 test_dir/test11 test_dir/test22
在评估点继承了父shell的条件。在实际启动所述子shell之前,父shell无法扩展子shell中的内容。
然而,正如@chepner所说:
没有理由在脚本中将其作为单行代码。单行程序旨在减少频繁执行的交互式命令的输入;在脚本中没有必要这样做,其中可读性应该被优先考虑。