Tengo un archivo strings.txt
con 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 xargs
con mv
:
cat strings.txt | xargs -I % mv %*faa ./Data
Pero mv
no lo ve %*faa
como una expresión regular e intenta buscar archivos con este nombre exacto (y, por supuesto, no puede encontrar ninguno). También intenté usar ls
pero 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 xargs
para entregar las cadenas strings.txt
a un script en línea bash
en lotes.
Para cada cadena, el script en línea bash
prueba si hay algún nombre de archivo que coincida con la cadena en el directorio actual (agregándolo *.faa
al final para crear un patrón) y, de ser así, se mueve al Data
directorio, que se supone que ya existe. .
La nullglob
opció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 xargs
esto:
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 mv
lí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.faa
que es el único partido.
Respuesta3
No es necesario xargs
ni 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=""