簡體   English   中英

bash:在額外條件下循環文件

[英]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工作流程來

  1. 列表項通過SED預處理每個圓角:在每個文件中添加一些內容
  2. 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?
  1. 您可以使用-f測試檢查文件是否存在,如果不存在,則將其break

     if [ ! -f "${pdbs}/${model}_${i}_FA.pdb" ]; then break fi 
  2. 您現有的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]將匹配文件foo1foo9 ,而不foo10foo99

不能執行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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM