[英]bash: looping over the files with extra conditions
在工作目錄中,有幾個文件根據文件名的后綴分為幾組。 這是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循環(例如,考慮只有1個文件的第4組)。 這是示例,但是無法正常工作
# 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?
您可以使用-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'
, 'y'
或'z'
,但它不匹配'0'
, 'q'
, 'r'
等。或者,也不能匹配任何大寫字母。
所以[1-99]
不被解釋為數字的范圍從1-99,它被解釋為一組包含在范圍從“1”到“9”的字符 ,再加上個性“9”。 因此,模式[1-9]
和[1-99]
是等效的,並且只會匹配字符'1'
至'9'
。 后一個表達式中的第二個9
是多余的。
但是,您仍然可以通過擴展glob實現所需的功能,可以通過使用shopt -s extglob
命令來啟用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
+([0-9])
表達式是擴展的glob表達式,它由兩部分組成: [0-9]
(在這時其含義應該很明顯)和封閉的+(...)
。
+(pattern)
語法是extglob
表達式,表示匹配pattern
一個或多個實例。 在這種情況下,我們的模式為[0-9]
,因此extglob
表達式+([0-9])
匹配任何數字0-9的字符串。
但是,您應該注意,這意味着它也匹配000000000
。 如果您只對大於或等於1的數字感興趣,則可以這樣做(啟用extglob
):
> echo f[1-9]*([0-9])
注意這里的*(pattern)
而不是+(pattern)
。 *
表示匹配零個或多個模式實例。 我們想要的,因為我們已經將第一個數字與[1-9]
匹配。 例如, f[1-9]+([0-9])
與文件名f1
不匹配。
您可能不希望在整個腳本中extglob
啟用extglob
,尤其是如果您在腳本中的其他位置有任何正則glob表達式,而這些表達式可能會意外地解釋為extglob
表達式。 要在完成后禁用extglob
,請執行以下操作:
shopt -u extglob
這里還有另一件事要注意。 如果全局模式與任何文件都不匹配,那么它將被解釋為原始字符串,並且保持不變。
例如:
> echo This_file_totally_does_not_exist*
This_file_totally_does_not_exist*
或更NpXynWT_com_340K
,假設第4種情況下文件為零,例如,沒有文件包含NpXynWT_com_340K
。 在這種情況下,如果嘗試使用包含NpXynWT_com_340K
的glob,則會將整個glob作為文字字符串獲取:
> shopt -s extglob
> echo NpXynWT_com_340K_[1-9]*([0-9])
echo NpXynWT_com_340K_[1-9]*([0-9])
這顯然不是你想要的,尤其是在你的腳本,你想中間cat
匹配的文件。 幸運的是,您可以設置另一個選項,以使不匹配的glob擴展為空:
> shopt -s nullglob
> echo This_file_totally_does_not_exist* # prints nothing
與extglob
,如果將nullglob
保留為extglob
,則腳本中的其他地方可能會有意外行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.