通配符 * 在 bash 脚本中未按预期方式运行
wildcard * not behaving in expected way in bash script
我有一个 bash 脚本,如下所示。我 运行 将其放在包含 input1.inp
等文件和 coords_i.xyz
和 submission.sub
等其他文件的目录中,以便对它们进行一些简单的修改:
#!/bin/bash
sed -i -e '25d' *.inp
echo "*xyz -2 2" >> *.inp
sed -n '3,7p' *_i.xyz >> *.inp
echo "Q -1 0 0 3" >> *.inp
echo "Q +1 0 0 -3" >> *.inp
echo "*" >> *.inp
sed -i -e s/"replace1"/"replace2"/g *.sub
rm *.out
如果我在这个目录中,并且我 运行 在终端中单独执行所有命令(在脚本中逐行),一切正常。但是,当我尝试将所有这些命令组合到如上所示的脚本中时,我收到一个错误 - 主要是在行 sed -i -e '25d' *.inp
之后,脚本停止并且在我的目录中创建了一个名为 *.inp
的文件。如果我在那之后分别尝试 运行 echo
命令,它会说该命令不明确(可能是因为这个 *.inp
文件的存在)。
为什么我的通配符在脚本中的工作方式与我 运行 它们在终端中单独和顺序地工作时的工作方式不同,我该怎么做才能使它们在脚本中正常工作?
以这种方式使用通配符是危险的;简单的建议是 "don't"。只评估一次,然后您可以在尝试使用它们之前检查它们的输出。
在下文中,我们定义了一个 assert_only_one
函数,当数组(从 glob 分配)包含的元素少于或多于一个时,该函数将停止您的脚本。因此,我们能够编写更清晰明确地描述我们所需行为的代码。
#!/usr/bin/env bash
shopt -s nullglob # Stop *.xyz evaluating to '*.xyz' if no such files exist
assert_only_one() {
local glob; glob=; shift
case $# in
0) echo "ERROR: No files matching $glob exist" >&2; exit 1;;
1) return 0;;
*) echo "ERROR: More than one file matching $glob exists:" >*2
printf ' %q\n' "$@" >&2
exit 1;;
esac
}
inp_files=( *.inp ); assert_only_one '*.inp' "${inp_files[@]}"
sub_files=( *.sub ); assert_only_one '*.sub' "${sub_files[@]}"
xyz_files=( *_i.xyz )
sed -i -e '25d' "${inp_files[0]}"
{
echo "*xyz -2 2"
sed -n '3,7p' "${xyz_files[@]}"
echo "Q -1 0 0 3"
echo "Q +1 0 0 -3"
echo "*"
} >>"${inp_files[0]}"
sed -i -e s/"replace1"/"replace2"/g -- "${sub_files[@]}"
rm -- *.out
我有一个 bash 脚本,如下所示。我 运行 将其放在包含 input1.inp
等文件和 coords_i.xyz
和 submission.sub
等其他文件的目录中,以便对它们进行一些简单的修改:
#!/bin/bash
sed -i -e '25d' *.inp
echo "*xyz -2 2" >> *.inp
sed -n '3,7p' *_i.xyz >> *.inp
echo "Q -1 0 0 3" >> *.inp
echo "Q +1 0 0 -3" >> *.inp
echo "*" >> *.inp
sed -i -e s/"replace1"/"replace2"/g *.sub
rm *.out
如果我在这个目录中,并且我 运行 在终端中单独执行所有命令(在脚本中逐行),一切正常。但是,当我尝试将所有这些命令组合到如上所示的脚本中时,我收到一个错误 - 主要是在行 sed -i -e '25d' *.inp
之后,脚本停止并且在我的目录中创建了一个名为 *.inp
的文件。如果我在那之后分别尝试 运行 echo
命令,它会说该命令不明确(可能是因为这个 *.inp
文件的存在)。
为什么我的通配符在脚本中的工作方式与我 运行 它们在终端中单独和顺序地工作时的工作方式不同,我该怎么做才能使它们在脚本中正常工作?
以这种方式使用通配符是危险的;简单的建议是 "don't"。只评估一次,然后您可以在尝试使用它们之前检查它们的输出。
在下文中,我们定义了一个 assert_only_one
函数,当数组(从 glob 分配)包含的元素少于或多于一个时,该函数将停止您的脚本。因此,我们能够编写更清晰明确地描述我们所需行为的代码。
#!/usr/bin/env bash
shopt -s nullglob # Stop *.xyz evaluating to '*.xyz' if no such files exist
assert_only_one() {
local glob; glob=; shift
case $# in
0) echo "ERROR: No files matching $glob exist" >&2; exit 1;;
1) return 0;;
*) echo "ERROR: More than one file matching $glob exists:" >*2
printf ' %q\n' "$@" >&2
exit 1;;
esac
}
inp_files=( *.inp ); assert_only_one '*.inp' "${inp_files[@]}"
sub_files=( *.sub ); assert_only_one '*.sub' "${sub_files[@]}"
xyz_files=( *_i.xyz )
sed -i -e '25d' "${inp_files[0]}"
{
echo "*xyz -2 2"
sed -n '3,7p' "${xyz_files[@]}"
echo "Q -1 0 0 3"
echo "Q +1 0 0 -3"
echo "*"
} >>"${inp_files[0]}"
sed -i -e s/"replace1"/"replace2"/g -- "${sub_files[@]}"
rm -- *.out