如何從清單中移動名稱以字串開頭的所有檔案?

如何從清單中移動名稱以字串開頭的所有檔案?

strings.txt我有一個包含字串列表的文件:

GCA_001677475.1
GCA_003410275.1
GCA_002310615.1
GCA_000007405.1
GCA_000219515.3

我的目錄中有許多文件,其名稱如下:

GCA_000005845.2_ASM584v2_protein.faa
GCA_000006925.2_ASM692v2_protein.faa
GCA_000007405.1_ASM740v1_protein.faa
GCA_000007445.1_ASM744v1_protein.faa
GCA_000008865.2_ASM886v2_protein.faa
GCA_000009565.2_ASM956v1_protein.faa

我只需要移動那些名稱以strings.txt.到目前為止,我已經嘗試使用xargswith mv

cat strings.txt | xargs -I % mv %*faa ./Data

mv%*faa視為正規表示式並嘗試尋找具有該確切名稱的檔案(當然它找不到任何檔案)。我也嘗試過使用,ls但它的工作方式是相同的:

cat strings.txt | xargs -I {} ls {}*faa

那我該怎麼做呢?

答案1

xargs bash -O nullglob -c '
    for prefix do
        set -- "$prefix"*.faa
        [ "$#" -gt 0 ] && mv -- "$@" ./Data
    done' sh <strings.txt

這用於xargs將字串批量提供strings.txt給內聯bash腳本。

對於每個字串,內聯bash腳本測試當前目錄中是否有任何與該字串匹配的檔案名稱(添加*.faa到末尾以建立模式),如果有,則將它們移動到該Data目錄,假設該目錄已經存在。

為內聯腳本設定shellnullglob選項,以確保建構的模式是否不是匹配任何內容,模式將被刪除(而不是保留未擴展)。

我正在明確測試模式是否匹配,因為您的範例中的某些字串與您顯示的任何檔案名稱都不匹配。這是透過將位置參數清單設為 glob 擴充的結果,然後測試清單的長度 ( $#) 是否大於零來完成的。

顯然你也可以這樣做,而不是像xargs這樣:

shopt -s nullglob

while IFS= read -r prefix; do
    set -- "$prefix"*.faa
    [ "$#" -gt 0 ] && mv -- "$@" ./Data
done <strings.txt

這仍然會失敗如果您的前綴字串之一碰巧匹配數千個檔案名稱(mv命令列會變得太長)。如果是這種情況,您可能會使用

shopt -s nullglob

while IFS= read -r prefix; do
    set -- "$prefix"*.faa
    if [ "$#" -gt 0 ]; then
        printf '%s\n' "$@" | xargs sh -c 'mv -- "$@" ./Data' sh
    fi
done <strings.txt

這是假設前綴字串和檔案名稱都不包含嵌入的換行符。

答案2

這是一個可能的解決方案:

cat strings.txt | xargs -I '%' find . -type f -name "%*" -exec mv -t your_path {} +

感動GCA_000007405.1_ASM740v1_protein.faa那是唯一的匹配。

答案3

不需要xargs或任何複雜的事情。如果所有檔案都位於同一目錄中,則執行以下操作就足夠了:

$ while read string; do 
    mv "$string"_* ./Data; 
  done < strings.txt 

或者,如果您的名字可以以 a 開頭-,或者其中可能有其他奇怪的字符,請使用:

$ while read -r string; do 
    mv -- "$string"_* ./Data; 
  done < strings.txt 

答案4

快速而骯髒的駭客:cat strings.txt| xargs -i sh -c 'mv {}* your/path/'>&/dev/null

更少更正確的駭客:export dir=$(ls -1); cat strings.txt| xargs -i sh -c 'grep "^{}" <<<$dir && mv {}* your/path'; dir=""

相關內容