リストから文字列で始まる名前を持つすべてのファイルを移動するにはどうすればよいですか?

リストから文字列で始まる名前を持つすべてのファイルを移動するにはどうすればよいですか?

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スクリプトは、各文字列について、現在のディレクトリ内に文字列に一致するファイル名があるかどうかをテストし (末尾に追加してパターンを作成します)、ある場合は、既に存在していると想定されるディレクトリ*.faaにそれらのファイル名を移動します。Data

シェルnullglobオプションはインラインスクリプトに設定されており、構築されたパターンがない何かに一致する場合、パターンは削除されます (展開されずに保持されるのではなく)。

例には、示されているファイル名のいずれにも一致しない文字列があるため、パターンが一致するかどうかを明示的にテストしています。これは、位置パラメータのリストを glob 展開の結果に設定し、リストの長さ ( $#) が 0 より大きいかどうかをテストすることによって行われます。

明らかに、次のようにしなくてもこれを行うことができます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

これは、プレフィックス文字列にもファイル名にも埋め込まれた改行が含まれていないことを前提としています。

答え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=""

関連情報