设置 "shopt -s nullglob" 时 sed 失败
sed fails when "shopt -s nullglob" is set
几天前,我启动了一个 bash 小脚本,该脚本应汇总一个文件夹中所有 PDF 的页数和文件大小。它现在工作得很好,但还有一件事我不明白。
如果设置了 shopt -s nullglob
,为什么 sed 总是失败?有人知道为什么会这样吗?
我在 Ubuntu 14.04 中使用 GNU Bash 4.3 和 sed 4.2.2。
set -u
set -e
folder=
overallfilesize=0
overallpages=0
numberoffiles=0
#If glob fails nothing should be returned
shopt -s nullglob
for file in $folder/*.pdf
do
# Disable empty string if glob fails
# (Necessary because otherwise sed fails ?:|)
#shopt -u nullglob
# This command is allowed to fail
set +e
pdfinfo="$(pdfinfo "$file" 2> /dev/null)"
ret=$?
set -e
if [[ $ret -eq 0 ]]
then
#Remove every non digit in the result
sedstring='s/[^0-9]//g'
filesize=$(echo -e "$pdfinfo" | grep -m 1 "File size:" | sed $sedstring)
pages=$(echo -e "$pdfinfo" | grep -m 1 "Pages:" | sed $sedstring)
overallfilesize=$(($overallfilesize + $filesize))
overallpages=$(($overallpages+$pages))
numberoffiles=$(($numberoffiles+1))
fi
done
echo -e "Processed files: $numberoffiles"
echo -e "Pagesum: $overallpages"
echo -e "Filesizesum [Bytes]: $overallfilesize"
这里有一个用于重现问题的更简单的测试用例:
#!/bin/bash
shopt -s nullglob
pattern='s/[^0-9]//g'
sed $pattern <<< foo42
预期输出:
42
实际输出:
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
(sed usage follows)
发生这种情况是因为 s/[^0-9]//g
是一个有效的 glob(匹配像 s/c/g
这样的目录结构),并且您要求 bash 解释它。由于您没有匹配的文件,nullglob
启动并完全删除该模式。
双引号防止分词和 glob 解释,这几乎总是你想要的:
#!/bin/bash
shopt -s nullglob
pattern='s/[^0-9]//g'
sed "$pattern" <<< foo42
这会产生预期的输出。
您应该始终对所有变量引用使用双引号,除非您有特殊原因不这样做。
几天前,我启动了一个 bash 小脚本,该脚本应汇总一个文件夹中所有 PDF 的页数和文件大小。它现在工作得很好,但还有一件事我不明白。
如果设置了 shopt -s nullglob
,为什么 sed 总是失败?有人知道为什么会这样吗?
我在 Ubuntu 14.04 中使用 GNU Bash 4.3 和 sed 4.2.2。
set -u
set -e
folder=
overallfilesize=0
overallpages=0
numberoffiles=0
#If glob fails nothing should be returned
shopt -s nullglob
for file in $folder/*.pdf
do
# Disable empty string if glob fails
# (Necessary because otherwise sed fails ?:|)
#shopt -u nullglob
# This command is allowed to fail
set +e
pdfinfo="$(pdfinfo "$file" 2> /dev/null)"
ret=$?
set -e
if [[ $ret -eq 0 ]]
then
#Remove every non digit in the result
sedstring='s/[^0-9]//g'
filesize=$(echo -e "$pdfinfo" | grep -m 1 "File size:" | sed $sedstring)
pages=$(echo -e "$pdfinfo" | grep -m 1 "Pages:" | sed $sedstring)
overallfilesize=$(($overallfilesize + $filesize))
overallpages=$(($overallpages+$pages))
numberoffiles=$(($numberoffiles+1))
fi
done
echo -e "Processed files: $numberoffiles"
echo -e "Pagesum: $overallpages"
echo -e "Filesizesum [Bytes]: $overallfilesize"
这里有一个用于重现问题的更简单的测试用例:
#!/bin/bash
shopt -s nullglob
pattern='s/[^0-9]//g'
sed $pattern <<< foo42
预期输出:
42
实际输出:
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
(sed usage follows)
发生这种情况是因为 s/[^0-9]//g
是一个有效的 glob(匹配像 s/c/g
这样的目录结构),并且您要求 bash 解释它。由于您没有匹配的文件,nullglob
启动并完全删除该模式。
双引号防止分词和 glob 解释,这几乎总是你想要的:
#!/bin/bash
shopt -s nullglob
pattern='s/[^0-9]//g'
sed "$pattern" <<< foo42
这会产生预期的输出。
您应该始终对所有变量引用使用双引号,除非您有特殊原因不这样做。