在工作目录中,有几个文件根据文件名的后缀分为几组。这是4组的示例:
# group 1 has 5 files
NpXynWT_apo_300K_1.pdb
NpXynWT_apo_300K_2.pdb
NpXynWT_apo_300K_3.pdb
NpXynWT_apo_300K_4.pdb
NpXynWT_apo_300K_5.pdb
# group 2 has two files
NpXynWT_apo_340K_1.pdb
NpXynWT_apo_340K_2.pdb
# group 3 has 4 files
NpXynWT_com_300K_1.pdb
NpXynWT_com_300K_2.pdb
NpXynWT_com_300K_3.pdb
NpXynWT_com_300K_4.pdb
# group 4 has 1 file
NpXynWT_com_340K_1.pdb
我已经为
编写了一个简单的bash工作流程cat
一起将属于同一组的预处理文件 这是我用于实现工作流程的脚本,在该脚本中,我创建了具有组名的数组,并根据文件索引从1到5对其进行循环
# list of 4 groups
systems=(NpXynWT_apo_300K NpXynWT_apo_340K NpXynWT_com_300K NpXynWT_com_340K)
# loop over the groups
for model in "${systems[@]}"; do
# loop over the files inside of each group
for i in {0001..0005}; do
# edit file via SED
sed -i "1 i\This is $i file of the group" "${pdbs}"/"${model}"_"$i"_FA.pdb
done
# after editing cat the pre-processed filles
cat "${pdbs}"/"${model}"_[1-5]_FA.pdb > "${output}/${model}.pdb"
done
改进此脚本的问题: 1)如何在内部(while)循环中添加一些检查条件(例如,通过IF语句)以考虑仅现有文件?在我的示例中,脚本始终根据一个组中的最大数目(这里是第一组中的5个文件)循环播放5个文件(每个组)
for i in {0001..0005}; do
我宁愿遍历给定组的所有现有文件,并在文件不存在的情况下中断while循环(例如,考虑第四个组只有一个文件)。这是示例,但是无法正常工作
# loop over the groups with the checking of the presence of the file
for model in "${systems[@]}"; do
i="0"
# loop over the files inside of each group
for i in {0001..9999}; do
if [ ! -f "${pdbs}/${model}_00${i}_FA.pdb" ]; then
echo 'File '${pdbs}/${model}_00${i}_FA.pdb' does not exits!'
break
else
# edit file via SED
sed -i "1 i\This is $i file of the group" "${pdbs}"/"${model}"_00"$i"_FA.pdb
i=$[$i+1]
fi
done
done
是否可以遍历该组中的任意数量的现有填充(而不是仅通过
来限制给定的大量文件)for i in {0001..9999}; do?
答案 0 :(得分:3)
您可以使用-f
测试来检查文件是否存在,如果不存在,可以检查break
:
if [ ! -f "${pdbs}/${model}_${i}_FA.pdb" ]; then
break
fi
您现有的cat
命令只对每个组中的现有文件进行计数,因为"${pdbs}"/"${model}"_[1-5]_FA.pdb
bash在此处执行文件名扩展,而不仅仅是将[1-5]
扩展为所有可能的文件价值观。您可以在以下示例中看到它:
> touch f1 f2 f5 # files f3 and f4 do not exist
> echo f[1-5]
f1 f2 f5
请注意,f[1-5]
并未扩展为f1 f2 f3 f4 f5
。
更新:
如果您希望全局表达式匹配以大于9的数字结尾的文件,则[1-n]
语法将不起作用。原因是[...]
语法定义了与单个字符匹配的模式。例如,表达式foo[1-9]
将匹配文件foo1
至foo9
,而不匹配foo10
或foo99
。
执行foo[1-99]
之类的操作不起作用,因为它并不意味着您可能会认为意味着什么。 []
的内部可以包含任意数量的单个字符或字符范围。例如,[1-9a-nxyz]
将匹配'1'
至'9'
,'a'
至'n'
的任何字符,或'x'
,{ {1}}或'y'
,但不匹配'z'
,'0'
,'q'
等。或者就此而言也不会匹配任何大写字母。
因此'r'
不能解释为1-99范围内的数字,它可以解释为包含范围为' 1”到“ 9”,再加上单个字符“ 9”。因此,模式[1-99]
和[1-9]
是等效的,并且将仅匹配字符[1-99]
至'1'
。后一个表达式中的第二个'9'
是多余的。
但是,您仍然可以通过扩展的glob实现所需的功能,可以使用命令9
启用它:
shopt -s extglob
> touch f1 f2 f5 f99 f100000 f129828523
> echo f[1-99999999999] # Doesn't work like you want it to
f1 f2 f5
> shopt -s extglob
> echo f+([0-9])
f1 f2 f5 f99 f100000 f129828523
表达式是一个扩展的glob表达式,它由两部分组成:+([0-9])
(在这时其含义应该很明显)和封闭的[0-9]
。
+(...)
语法是+(pattern)
表达式,表示匹配extglob
的一个或多个实例。在这种情况下,我们的模式为pattern
,因此[0-9]
表达式extglob
与任何数字0-9的字符串匹配。
但是,您应该注意,这意味着它也与+([0-9])
之类的东西匹配。如果您只对大于或等于1的数字感兴趣,则可以这样做(启用000000000
):
extglob
请注意此处的> echo f[1-9]*([0-9])
而不是*(pattern)
。 +(pattern)
表示匹配零或更多模式实例。我们想要的,因为我们已经将第一个数字与*
进行了匹配。例如,[1-9]
与文件名f[1-9]+([0-9])
不匹配。
您可能不希望在整个脚本中都启用f1
,特别是如果您在脚本中的其他位置有任何正则glob表达式,而这些表达式可能会意外地解释为extglob
表达式。要在完成操作后禁用extglob
,请执行以下操作:
extglob
这里还有另一件事要注意。如果全局模式与 any 文件不匹配,那么它将被解释为原始字符串,并且保持不变。
例如:
shopt -u extglob
或更具体的说,假设第4种情况的文件数为零,例如没有包含> echo This_file_totally_does_not_exist*
This_file_totally_does_not_exist*
的文件。在这种情况下,如果尝试使用包含NpXynWT_com_340K
的glob,则会将整个glob作为文字字符串获取:
NpXynWT_com_340K
这显然不是您想要的,尤其是在脚本的中间,您尝试> shopt -s extglob
> echo NpXynWT_com_340K_[1-9]*([0-9])
echo NpXynWT_com_340K_[1-9]*([0-9])
匹配文件。幸运的是,您可以设置另一个选项,以使不匹配的glob扩展为空:
cat
与> shopt -s nullglob
> echo This_file_totally_does_not_exist* # prints nothing
一样,如果您将extglob
保留为打开状态,则脚本中的其他地方可能会有意外的行为。