Antecedentes
En Linux puedes:
- Listar un grupo de archivos con
ls Filename*
- Eliminar un grupo de archivos con
rm Filename*
- Mover un grupo de archivos con
mv Filename* /New/Directory
- Pero no puede copiar un grupo de archivos con:
cp Filename* *.bak
Cambiar el cp
comando de Linux para copiar el grupo de archivos
Tengo un grupo de archivos que me gustaría copiar sin ingresar los nombres uno por uno y usando el cp
comando:
$ ls gmail-meta3*
gmail-meta3 gmail-meta3-REC-1558392194-26467821
gmail-meta3-LAB-1558392194-26467821 gmail-meta3-YAD-1558392194-26467821
¿Cómo puedo usar algo como el viejo comando de DOS copy gmail-meta3* *.bak
?
No quiero escribir un comando similar cuatro veces:
cp gmail-meta3-LAB-1558392194-26467821 gmail-meta3-LAB-1558392194-26467821.bak
Estoy buscando un script / función / aplicación que acepte parámetros para el grupo de nombre de archivo antiguo y nuevo y no algo con nombres de archivo codificados. Por ejemplo, un usuario puede escribir:
copy gmail-meta3* *.bak
o pueden escribir:
copy gmail-meta3* save-*
command-line
cp
ms-dos
WinEunuuchs2Unix
fuente
fuente
touch aa ab ba; mkdir bb; cp a* b*; ls *
*
para los nombres de los archivos de origen, pero no para los nombres de los archivos de destino. Como tal, el comodín sustituto (creo que##
fue sugerido pero me estoy inclinando hacia%
) tendrá que usarse para el objetivo. Creo que esto es lo que estás reforzando? No esperaba cambiar elcp
comando en absoluto. Simplemente cree una secuencia de comandos de envoltura llamadacopy
que emuló (dentro de lo razonable) el comando de copia de DOS.Respuestas:
Aquí hay un ejemplo de un uso atípico de
sed
, que es aplicable para esta tarea:De esta manera, en realidad,
sed
no cambiará los archivos, porque no proporcionamos ningún comando''
, pero debido a la opción-i[suffix]
, creará una copia de seguridad de cada archivo. Encontré este enfoque cuando estaba buscando ¿Hay alguna forma de crear una copia de seguridad de un archivo, sin escribir su nombre dos veces?fuente
$ time sed -i.bak '' gmail-meta3*
=real 0m0.069s
real 0m0.037s
. Si los archivos borrados y correr por segunda vez cerca decp
la velocidad:real 0m0.051s
.sed
es más rápido cuando ya existen archivos de destino, perocp
es más lento cuando existen archivos de destino. De hecho, enjuago los cachés y las memorias intermedias en lugar desync
cuando hago grandes pruebas de tiempo, pero esta vez no lo hice. Como esto puede estar divagando en una telenovela completamente diferente fuera del tema, lamento haber compartido los resultados de mi prueba :( ¿Es demasiado tarde para fingir que esta conversación nunca sucedió? . Tampoco es un disco duro, es un SSD Samsung Pro 960 NVMe en 4 canales.free
comando. Las escrituras reales en el dispositivo tienen lugar en un momento elegido por un algoritmo que tiene en cuenta la antigüedad de la memoria caché y la presión de la memoria en la máquina. Si está probando varias pruebas, las primeras lecturas de archivo saldrán del disco, pero las lecturas posteriores probablemente saldrán directamente de la memoria (veasync; echo 3 > /proc/sys/vm/drop_caches
).cp
comando, pero no puedo decir que haya una diferencia de rendimiento significativa .Puedes usar
find
:Eso encontrará en el directorio actual
.
todos los archivos con un nombre que coincida con el patrón global (tenga en cuenta las comillas simples alrededor del patrón para evitar el bloqueo de shell). Para cada archivo encontrado, secp
ejecutará de nombre a nombre.bak. Los \; al final asegura que hará cada archivo individualmente en lugar de pasarlos todos a la vez. La profundidad máxima como 1 solo busca en el directorio actual en lugar de recurrir hacia abajo.fuente
find . -max-depth 1 -name '"$1"'' -exec cp "{}" "{}$2" \;
cuando $ 1 sea fuente y $ 2 sea extensión?Puedes usar un
for
bucle conbash
. Normalmente, simplemente lo escribiría como una sola línea porque esta no es una tarea que realizo a menudo:Sin embargo, si lo necesita como un script:
El uso es similar a
rename
. Probar:fuente
$ time for f in gmail-meta3* ; do cp -a "$f" "${f}.bak" ; done
=real 0m0.046s
0.046
segundos, lo que significa 0 segundos para la percepción humana. Solo estaba tratando de mostrar cómo estaba probando las respuestas publicadas y transmitiendo cositas interesantes a los espectadores que vieron elsed
comando anterior. O al menos estaba interesado en compararmesed
concp
...cp
es más rápida que la solución consed
. Así que es motivo de celebración :)-a
es un operador de prueba no estándar. ¿Por qué no usar-e
? (2) "No se puede crear el directorio temporal". es un mensaje de error algo engañoso. (3) ¿Por qué no solo usarmktemp -d
? (4) Debe probar los estados de salida. Por ejemplo, deberías decir! mkdir "$FOLDER" && echo "Unable to create temporary directory." && return 1
omkdir "$FOLDER" || { echo "Unable to create temporary directory."; return 1;}
. Del mismo modo paracp
yrename
(y tal vez inclusopushd
, si quieres tener cuidado). … (Continúa)$@
; por ejemplo"$@"
. (5b) No es necesario usar{
y}
cuando hace referencia a las variables de la forma en que lo está haciendo ("${FOLDER}"
,"${PATTERN}"
y"${file}"
); acaba de hacer"$FOLDER"
,"$PATTERN"
y"$file"
. (6) Esto supone que los archivos están en el directorio actual.cps 's/$/.bak/' d/foo
copiarád/foo
afoo.bak
en el directorio actual, nod/foo.bak
.Lo más cercano que probablemente llegará al paradigma de DOS es
mcp
(desde elmmv
paquete):Si
zsh
está disponible, suzmv
módulo contribuido está quizás un poco más cerca:Sin
ls
embargo, evitaría : una variante en su propia respuesta que sea segura para los espacios en blanco (incluidas las nuevas líneas) seríao quizás
fuente
mmv
es el paquete, pero en los comentarios dices que el comando esmcp
pero luego en el comando que usas,mmv
que también es un comando en elmmv
paquete. Me gusta la dirección de losprintf
ejemplos y en un guión pulido me aseguraría de que se pasaran $ 1 y $ 2. +1 por hacer rodar la pelota :)mcp
es solo un sinónimo demmv -c
printf
comando que nunca he usado realmente. ¿Estás diciendoprintf '%s\0' "$1"*
que funcionaría sigmail-meta3
se pasara como parámetro 1?cps gmail-meta3*
y luego escribaprintf '%s\0
"$ @" | mientras ... `en la función. O simplemente usefor f; do cp -- "$f" "$f.bak"; done
(como la respuesta de xiota , pero como una función)zmv
usted puede usar el modo "reemplazo de comodines", que me resulta un poco más fácil de asimilar:zmv -W -C 'gmail-meta3*' '*.bak'
solución única rsync
Si solo desea hacer una copia de seguridad de sus archivos, puede copiarlos en un nuevo directorio
rsync /path/to/dir/Filename* /path/to/backupdirectory
Esto copiará los
Filename
archivos de/path/to/dir/
a/path/to/backupdirectory
.rsync + filerename
Si desea que sus archivos de respaldo tengan un sufijo, las cosas se ponen difíciles con
rsync
...rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak
Esto sobrescribiría los archivos existentes ... con los archivos existentes (
-I
) pero solo si son (-u
) más nuevos (que no lo son) y crean una copia de seguridad, con un sufijo.También puede hacerlo en el mismo directorio. Pero mejor excluir las copias de seguridad existentes.
rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak --exclude '*.bak'
fuente
rsycnc
así que voté, pero un método más simple seríacp Filename* /path/to/backup/dir
porque los archivos no necesitarían*.bak
uniquifier si estuvieran en un directorio separado.Este debe hacer lo solicitado:
Uso:
Elegí
?
porque#
debe citarse cuando es el primer carácter del patrón; de lo contrario, se reconoce como el comienzo de un comentario.Prueba:
Algunas versiones anteriores del script para agregar un sufijo:
Similar a la respuesta de @ WinEunuuchs2Unix, pero creo que es más flexible y no analiza
ls
:Pon esto en tu
.bashrc
.Uso:
Alternativa, con el sufijo como último argumento ( vía y vía ):
Uso:
fuente
copy gmail-meta3* old-meta3*
. En mi respuesta no pude encontrar la forma de ingresar*
al nombre del destino como mi pregunta solicitada ...*
es interpretado por el shell, por lo que la función no lo sabrá. Necesitaría algún otro carácter o citarlo, luego reemplácelo con el nombre de archivo original dentro de la función.#
podría usarse como comodín de reemplazo*
. Entonces podrías escribircopy filenames# save-#
. Creo que querrías que el carácter comodín sea el mismo para el origen y el destino.Escribí esta frase en mi
~/.bashrc
.find
Supongo que se pueden publicar respuestas mucho mejores usando . Incluso se podrían escribir mejores respuestas en C. Esperemos que este Q&A ponga en marcha la pelota para obtener mejores respuestas:for f in "$1"*; do
:$1
es elgmail-meta3
parámetro yf
es la lista de archivos que coinciden. Combinado esto significa para gmail-meta3, gmail-meta3-LAB-9999, etc., haga lo siguiente[[ ! "$f" == *"$2" ]] &&
:$f
es lo mismo quef
arriba.$2
es el.bak
parámetro pasado Combinado esto significa que si el nombre de archivo no termina en.bak
(porque no queremos copiar.bak
y crear.bak.bak
), haga lo siguientecp -a "$f" "$f$2";
copie gmail-meta3 en gmail-meta3.bak, etc.done
: retrocede y toma el siguiente nombre de archivo en lagmail-meta3
lista *.cps gmail-meta3 .bak
Salida de muestraUsando la pregunta como ejemplo aquí es cómo se ve en acción:
Nota: Esto usa la
-a
bandera con elcp
comando para preservar las marcas de tiempo y darle una mejor comprensión de sus copias de seguridad de archivos.Observe cómo las copias de archivo tienen exactamente la misma fecha y hora que los originales. Si
-a
se omitiera el parámetro, se les daría la fecha y hora actuales y no se vería como una verdadera copia de seguridad, excepto que el tamaño del archivo sería el mismo.fuente
ls
find
, supongo que eres consciente de los peligros del análisisls
. Pero en su caso tampoco es necesario: simplementefor file in "$1"*; do copy -a "$file" "$file$2"; done
, esto es completamente seguro y mucho más simple que cualquier tipo de indirección a través dels
ofind
y unwhile
bucle.Otro método para cumplir su requisito es copiar los archivos en un directorio temporal y usar el
rename
comando para cambiarles el nombre.Si lo necesita como script, puede usarlo así
Y puedes usarlo así:
Esto es un ejemplo
fuente