Como mover todos os arquivos com nomes começando com uma string de uma lista?

Como mover todos os arquivos com nomes começando com uma string de uma lista?

Eu tenho um arquivo strings.txtcom uma lista de strings:

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

E tenho muitos arquivos em um diretório com nomes como:

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

Preciso mover apenas os arquivos cujos nomes começam com um padrão de strings.txt. Até agora tentei usar xargscom mv:

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

Mas mvnão vê %*faacomo regex e tenta encontrar arquivos com esse nome exato (e é claro que não consegue encontrar nenhum). Eu também tentei usar ls, mas funciona da mesma maneira:

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

Então, como posso fazer isso?

Responder1

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

Isso é usado xargspara fornecer as strings strings.txtpara um script em linha bashem lotes.

Para cada string, o script em linha bashtesta se há algum nome de arquivo que corresponda à string no diretório atual (adicionando *.faaao final para criar um padrão) e, em caso afirmativo, eles são movidos para o Datadiretório, que se presume já existir .

A nullglobopção shell é definida para o script in-line para garantir que, se o padrão construído nãonãocorresponder a qualquer coisa, o padrão será removido (em vez de retido sem expansão).

Estou testando explicitamente se o padrão corresponde porque há strings no seu exemplo que não correspondem a nenhum dos nomes de arquivo mostrados. Isso é feito definindo a lista de parâmetros posicionais como o resultado da expansão global e testando se o comprimento da lista ( $#) é maior que zero.

Obviamente, você também poderia ter feito isso sem xargsisso:

shopt -s nullglob

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

Isso ainda seriafalharse uma de suas strings de prefixo correspondesse a muitos milhares de nomes de arquivos (a mvlinha de comando ficaria muito longa). Se for esse o caso, você possivelmente usaria

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

Isso pressupõe que nem as strings de prefixo nem os nomes de arquivos contenham novas linhas incorporadas.

Responder2

Esta é uma solução possível:

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

Movido GCA_000007405.1_ASM740v1_protein.faaque é a única partida.

Responder3

Não há necessidade xargsnem nada complicado. Se todos os arquivos estiverem no mesmo diretório, será suficiente fazer:

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

Ou, se seus nomes puderem começar com a -ou se você tiver outros caracteres estranhos neles, use:

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

Responder4

Hack rápido e sujo:cat strings.txt| xargs -i sh -c 'mv {}* your/path/'>&/dev/null

Hack menos mais correto:export dir=$(ls -1); cat strings.txt| xargs -i sh -c 'grep "^{}" <<<$dir && mv {}* your/path'; dir=""

informação relacionada