¿Cómo puede mover (o copiar) todos los archivos a un directorio con el mismo prefijo de nombre de archivo?

9

Usando Bash

Digamos que tengo un montón de archivos colocados aleatoriamente en un directorio principal ~/src, quiero tomar todos los archivos que coinciden con un determinado sufijo y moverlos (o copiarlos) a un ~/distdirectorio.

Asumamos para este propósito que todos los nombres de archivo tienen esta convención de nomenclatura:

<filename_prefix>.<filename_suffix>

Descubrí que esta era una forma rápida de obtener todos los archivos con un particular filename_suffixy ponerlos en una carpeta dist:

mkdir ~/dst
find source -name "*.xxx" -exec mv -i {} -t ~/dst \;

Ahora un paso más allá ... ¿cómo puedo usar la salida de find, en este caso filename, y usar filename_prefixpara generar un directorio con el mismo nombre ~/disty luego mover (o copiar) todos los archivos con ese prefijo en el directorio apropiado?

mkdir ~/dst
find source -name "*.xrt,*.ini,*.moo" -exec mv -i {} -t ~/dst \;

Esencialmente, ¿cómo cambio el comando anterior (o tal vez uso otro comando) para crear una estructura como esta?

(SALIDA)

~/dist/people/people.xrt
~/dist/games/games.xrt
~/dist/games/games.moo
~/dist/games/games.ini
~/dist/monkeys/monkeys.ini
~/dist/monkeys/monkeys.xrt

de un árbol de directorios como este?

(ENTRADA)

~/src/xrt/people.xrt
~/src/xrt/games.xrt
~/src/conf/games.ini
~/src/pack/monkeys.xrt
~/src/e344/games.moo
~/src/e344/monkeys.moo
~/src/en-us/monkeys.ini
qodeninja
fuente

Respuestas:

10

Sería un infierno decir findqué hacer en este caso.

Mejor usar la cáscara:

for i in **/*.{xrt,ini,moo}; do
  FILE=$(basename "$i")
  DIR=~/dst/${FILE%.*}
  echo mkdir -p -- "$DIR"
  echo mv -i -t "$DIR" -- "$i"
done

Úselo shopt -s globstarpara hacer que el **globo funcione (¡o use zsh!). Y elimine los echos más tarde si el comando imprime lo que desea.

Stéphane Gimenez
fuente
usando bash es esto lo mismo?
qodeninja
@codeninja shopt -s globstar, mira mi edición. Si solo hay dos niveles, puede usar */*.*y el fragmento funcionará en cualquier shell.
Gilles 'SO- deja de ser malvado'
2

hacer trampa encontrar la línea de comando:

find source -name "*.xrt,*.ini,*.moo" -exec env file={} bash -c 'base="$(basename "$file")";dir="dst/${base%.*}";mkdir -p "$dir";cp "$file" "$dir"' \;

En realidad, una solución para llamar a bash script en find LOL.

= P

yuyichao
fuente
1
¡Adivina qué sucede si hay un archivo que se llama ... happy rm -rf /! Este tipo de código merece un -1.
Stéphane Gimenez
Su edición no es suficiente: digamos que hizo clic en un enlace y lo descargó Yay" rm -rf / "Rox0r.avi, nuevamente hay un problema ...
Stéphane Gimenez
(Y no hay forma de hacer que este tipo de sustitución sea seguro).
Stéphane Gimenez
1
Ah, tal vez es posible hacer esto de manera diferente. Parece que las siguientes obras: -exec bash -c 'command which uses "$1"' bash '{}' ';'. Bueno, de todos modos no tiene sentido.
Stéphane Gimenez
1
@ StéphaneGimenez hecho, bash no es lo único que se puede usar. LOL
yuyichao