何时在bash脚本中执行语法验证?

时间:2016-12-01 14:40:53

标签: bash syntax glob

我有以下脚本:

#!/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

立即显示相同的错误消息,从而确认在执行该行之前引发了错误消息。

为什么?有办法吗?

2 个答案:

答案 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所说:

  

没有理由在脚本中将其作为单行代码。单行程序旨在减少频繁执行的交互式命令的输入;在脚本中没有必要这样做,其中可读性应该被优先考虑。