如何从列表中移动名称以字符串开头的所有文件?

如何从列表中移动名称以字符串开头的所有文件?

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选项,以确保构造的模式是否不是匹配任何内容,模式将被删除(而不是保留未扩展)。

我正在明确测试模式是否匹配,因为您的示例中的某些字符串与您显示的任何文件名都不匹配。这是通过将位置参数列表设置为全局扩展的结果,然后测试列表的长度 ( $#) 是否大于零来完成的。

显然你也可以这样做,而不像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=""

相关内容