¿Cómo copio varios archivos con comodines?


42

Tengo una carpeta con varios archivos ABC. * (Hay aproximadamente 100 de estos archivos). Quiero duplicarlos todos en archivos nuevos con nombres que comiencen con DEF. *

Entonces yo quiero

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

copiado a

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

¿Cuál es la forma más sencilla de hacer esto con un comando por lotes (en BASH o similar)? Estoy pensando en algo relacionado con sed o awk o xargs, pero tengo dificultades para descubrir la sintaxis. Podría escribir un script de Python, pero creo que probablemente haya una solución de línea de comandos que no sea demasiado complicada.


Un mcadministrador de archivos venerable tiene un soporte más extenso para este tipo de cambios de nombre masivos.
oakad

@oakad tartampoco es un pollo de primavera. Vea mi respuesta para un ejemplo.
mikeserv

Respuestas:


41

¿Qué tal algo como esto en bash:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

puedes probarlo poniendo echo delante del comando cp:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done

Perfecto. incluso más simple de lo que imaginaba.
Octopus

Será lo suficientemente bueno en la mayoría de los casos, pero verificar con el eco es crucial aquí. Nunca hagas esto en un guión . Para obtener más información, lea las trampas de bash
pawel7318

@ pawel7318, el enlace que proporcionó, aunque es un excelente consejo, no parece aplicarse al comando dado anteriormente. Los únicos casos extremos que veo con este comando son: (1) No comprueba si el archivo de destino ya existe ni si el archivo de destino ya existe como un directorio (que copiaría el archivo en el directorio, conservando su nombre actual), y (2) si hay tantos archivos que la expansión global no puede caber en una sola línea de comando.
Comodín el

1
Me sale esto: cp /usr/local/lib/libboost* /usr/local/lib/libboost*con la verificación de eco.
Tomáš Zato

8

Para hacer esto de manera eficiente con una gran cantidad de archivos, es mejor evitar iniciar un cpproceso diferente para cada uno. Una forma sería copiarlos y luego renombrarlos usando prename( renameestá enlazado a esto por defecto en distribuciones basadas en Debian). Usando esto y Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Actualizar

En realidad, paxpuede ser una mejor manera de ir aquí:

pax -rws '/^ABC/DEF/' ABC.* .

Desafortunadamente, a pesar de paxser POSIX y Linux Standard Base, pocas distribuciones lo incluyen por defecto.


Buen toque usando: como separador para evitar escapar.
Clayton Stanley

5

tar Hará esto por usted realmente rápido.

PRUEBA

Primero creé 2 directorios y 10 archivos:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Luego los copié:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

TRANSFORMAR

Entonces GNU taraceptará un sed --transform=EXPRESSIONcambio de nombre de archivo. Esto incluso puede renombrar solo algunos de los archivos. Por ejemplo:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

Entonces esa es una ventaja.

CORRIENTE

También considere que esto es solo dos tarprocesos, y que no se alterará independientemente de su recuento de archivos.

tar | tar

tarestá tan optimizado como podría desear que sea. Esto nunca tendrá problemas de conteo de argumentos o procesos secundarios fuera de control. Esto es solo A> B hecho.

ARGUMENTOS

Utilizo 7 argumentos distintos combinados entre mis dos tarprocesos aquí. El más importante se enumera aquí primero:

-stdout / stdin : esto informa tarque transmitirá su entrada o salida hacia o desde la stdin/stdoutcual interpretará correctamente dependiendo de si está construyendo o extrayendo un archivo.

-ccrear : esto le dice tara construir el archivo. El siguiente argumento tarespera es ...

-farchivo : especificamos que tarfuncionará con un fileobjeto en lugar de un dispositivo de cinta o lo que sea. Y el archivo con el que estará trabajando, como se señaló anteriormente, es stdin/stdout, en otras palabras, nuestro |pipe.

./*todos $ PWD / archivos : no hay mucho que explicar aquí, excepto que el argumento del archivo es lo primero, y -luego ./*.

... y al otro lado del |pipe...

-Ccambiar directorio : esto informa tarque necesita cambiar al directorio que especifico antes de realizar cualquier otra acción, de manera efectiva justo cd ../test2antes de la extracción.

--transform='s/ed/EXPR/'- Como ya se mencionó, esto hizo el cambio de nombre. Pero los documentos indican que puede tomar cualquier sedexpresión o //flag.

-xextraer : después de los tarcambios en nuestro directorio de destino y recibir nuestras instrucciones de cambio de nombre, le indicamos que comience a extraer todos los archivos en su directorio actual del -f - |pipearchivo de almacenamiento. No hay misterio


1
Aquí está la paxsolución para esta pregunta. Lo agregaría a mi respuesta, pero creo que es más adecuado aquí -pax -rws '/^ABC/DEF/' ABC.* .
Graeme

@Graeme - woah - ¡eso es mucho mejor! ¡Hombre, también supera el cambio de nombre de perla! Debería poner esto en su respuesta, paxse especifica POSIX, de ahí el pax.
mikeserv

paxpuede ser POSIX, pero desafortunadamente rara vez se instala por defecto.
Graeme

4

Si no le importa usar una herramienta menos estándar, le recomiendo usar mmv (movimiento en masa) que fue escrito para este tipo de tareas. Usando mcp(copia masiva), que es parte de la suite, simplemente podría hacer

mcp "ABC.*" "DEF.#1"

No es exactamente fácil encontrar paquetes de descarga. Aquí se puede encontrar el paquete Debian actual (que Arch también usa en AUR) para compilar en casa .


se instala en ubuntu 15.10 fuera de la caja,apt-get install mmv
Thufir

2

En zsh, ponga las siguientes líneas en su .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Luego, en la línea de comando, puede ejecutar

zcp 'ABC(.*)' 'DEF$1'

o simplemente

zcp -W ABC.* DEF.*

En otro shell, siempre que tenga instalado zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

1

Podrías hacer esto:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done

Tal vez hay algo que no veo, pero ¿cómo configuro varios destinos? Estoy usando el bucle for para obtener cada uno. Probé el código de antemano y funcionó como se esperaba, por lo que agradecería su explicación.
Sara Fauzia

Esa es mi mala, leí mal tu respuesta. :-)
Chris Down

¿Cómo debo leer el "${i#*.}"bit?
dumbledad el

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.