¿Cómo mover todos los archivos con nombres que comienzan con una cadena de una lista?

¿Cómo mover todos los archivos con nombres que comienzan con una cadena de una lista?

Tengo un archivo strings.txtcon una lista de cadenas:

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

Y tengo muchos archivos en un directorio con nombres 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

Necesito mover sólo aquellos archivos cuyos nombres comiencen con un patrón de strings.txt. Hasta ahora he intentado usar xargscon mv:

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

Pero mvno lo ve %*faacomo una expresión regular e intenta buscar archivos con este nombre exacto (y, por supuesto, no puede encontrar ninguno). También intenté usar lspero funciona de la misma manera:

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

Entonces, ¿cómo puedo hacer eso?

Respuesta1

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

Esto se utiliza xargspara entregar las cadenas strings.txta un script en línea bashen lotes.

Para cada cadena, el script en línea bashprueba si hay algún nombre de archivo que coincida con la cadena en el directorio actual (agregándolo *.faaal final para crear un patrón) y, de ser así, se mueve al Datadirectorio, que se supone que ya existe. .

La nullglobopción Shell está configurada para el script en línea para garantizar que si el patrón construido nonocoincide con cualquier cosa, el patrón se elimina (en lugar de conservarse sin expandir).

Estoy probando explícitamente si el patrón coincide porque hay cadenas en su ejemplo que no coinciden con ninguno de los nombres de archivo que muestra. Esto se hace configurando la lista de parámetros posicionales como el resultado de la expansión global y luego probando si la longitud de la lista ( $#) es mayor que cero.

Obviamente también podrías haber hecho esto sin xargsesto:

shopt -s nullglob

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

Esto todavíafallarsi una de sus cadenas de prefijo coincidiera con muchos miles de nombres de archivos (la mvlínea de comando se volvería demasiado larga). Si ese es el caso, posiblemente usarías

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

Esto supone que ni las cadenas de prefijos ni los nombres de archivos contienen nuevas líneas incrustadas.

Respuesta2

Esta es una posible solución:

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

Movido GCA_000007405.1_ASM740v1_protein.faaque es el único partido.

Respuesta3

No es necesario xargsni nada complicado. Si todos los archivos están en el mismo directorio, debería ser suficiente con hacer:

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

O, si sus nombres pueden comenzar con a -o puede tener otros caracteres extraños, use:

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

Respuesta4

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

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

información relacionada