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

问题描述 投票:1回答:2

我有以下脚本:

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

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

这是为什么 ?有办法吗?

bash syntax glob
2个回答
4
投票

bash逐行处理脚本。在第一种情况下,shopt -s extglob已经在解析for循环时执行。在错误的情况下,您有一行在解析后将被识别为由;分隔的两个命令。然而,这意味着当shopt -x extglob需要识别扩展模式bash时,+([0-9])尚未被执行。

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


0
投票

Bash逐行读取脚本或输入。然后它使用元字符(| & ; ( ) < > 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

要么:

$ 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无法扩展子shell内的内容。

但是,正如@chepner所说:

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

© www.soinside.com 2019 - 2024. All rights reserved.