名前が文字列で始まるすべてのファイルをリストから移動するには?

名前が文字列で始まるすべてのファイルをリストから移動するには?

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使ってみました。xargsmv

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.txtbash

各文字列について、インラインスクリプトは現在のディレクトリにそのbash文字列(パターンを作成するために最後に追加されたもの)と一致するファイル名があるかどうかをテストし、その場合はそのファイルがすでに存在すると仮定してそのディレクトリに移動します。*.faaData

インラインスクリプトのシェルオプションを設定して構成されたnullglobパターンいいえ何でも一致すると、パターンは削除されます(拡張されていないままではありません)。

あなたの例の一部の文字列があなたが表示したファイル名と一致しないため、パターン一致を明示的にテストしています。これは、位置引数リストをグローバル拡張結果に設定し、リストの長さ()がゼロより大きいかどうかをテストすることによって$#行われます。

明らかに、次のように代わりにこれを行うこともできますxargs

shopt -s nullglob

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

これはまだ失敗するプレフィックス文字列の1つが何千ものファイル名と一致する場合(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

これは、プレフィックス文字列またはファイル名に改行文字が含まれていないと仮定します。

おすすめ記事