¿Cómo copiar y renombrar archivos encontrados en "buscar" funcionan Linux?


17

Tengo una carpeta llamada /home/user/tempsque tiene 487 carpetas. En cada carpeta tengo un archivo llamado thumb.png.

Quiero copiar todos los archivos llamados thumb.png a una carpeta separada y cambiarles el nombre en función de la carpeta de la que provienen.


renombrarlos, ¿cómo? Si reemplaza el delimitador de directorio con algo, digamos subrayado (_), puede obtener colisiones con archivos, que ya contienen un subrayado. Eso es cierto para cada personaje válido, y al lado de / y \ 0, que están prohibidos en los nombres de archivo, no hay un puerto seguro: cualquier personaje puede producir una colisión.
usuario desconocido el

¿Las carpetas tienen subcarpetas, o simplemente una estructura de carpetas amplia y simple?
usuario desconocido

Respuestas:


8

Aqui tienes:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

editar:

La sabiduría canónica, por cierto, es que usar findesto es una mala idea: simplemente usar la expansión de shell es mucho más confiable. Además, esto suponebash , pero supongo que es una suposición segura :)

editar 2:

para mayor claridad, lo desglosaré:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

Los detalles sobre la ${var/Pattern/Replacement}construcción se pueden encontrar aquí .

las comillas en la cplínea son importantes para manejar espacios y líneas nuevas, etc. en los nombres de archivo.


nuevo_archivo = nueva_carpeta? ¿Cuál es el propósito de la barra diagonal inversa frente a la barra diagonal new_file/\/thumb?
usuario desconocido

1
@user: ${VARIABLE/PATTTERN/REPLACEMENT}produce el valor de VARIABLEpero con el patrón reemplazado por el texto de reemplazo. Aquí el patrón es /thumb( es /necesario escapar para que no se vea ${new_file//PATTERN/REPLACEMENT}, lo que lo convierte en un reemplazo global en lugar de un reemplazo de primera aparición) y el texto de reemplazo está vacío.
Gilles 'SO- deja de ser malvado'

Por supuesto, ahora lo veo. :)
usuario desconocido el

1
Está asumiendo que los directorios 487 están directamente debajo /home/user/temps, lo que no está claro en la pregunta. Si no lo son, necesita encontrar o **.
Gilles 'SO- deja de ser malvado'

@Gilles - De hecho, así es como leí la pregunta. Aprecio el punto, sin embargo :)
Simon

5

Esto funciona para subdirectorios arbitrariamente profundos:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

La parte interesante es la expansión de parámetros ${NAME//\//_} . Toma el contenido de NAME, y reemplaza cada ocurrencia de /con _.

Nota: el resultado depende del directorio de trabajo y del parámetro de ruta para buscar. Ejecuté el comando desde el directorio padre de temps. Reemplazar cpcon echopara experimentar.


Falla en archivos que contienen una nueva línea en su nombre.
usuario desconocido

Bueno, eso funcionó muy bien. Una cosa más, también tengo algunos archivos zip en algunos subdirectorios. ¿Es posible extraer imgas de allí también? recuerda 'zip no alquitrán'
Mirage

1

Código de ayuda breve:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

vamos a llamarlo 'deslash.sh' y hacerlo ejecutable. Llámalo con:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

Fallará si existe una colisión

a/b/thumb.png # and 
a_b/thumb.png 

Pero eso es inevitable.


0

Prueba esto

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

Editar

He agregado citas en caso de que alguno de sus nombres de directorio tenga caracteres de espacio en blanco incrustados en ellos.

También he cambiado esto para que solo imprima los comandos que se ejecutarán. Examine la salida del script para asegurarse de que todos los archivos / nombres de ruta se vean correctos. Cuando esté seguro de que no hay problemas con los comandos que se ejecutarán, elimine el echo.


Tengo algunos archivos png en algunas subcarpetas más, ¿funcionará
Mirage

para mi carpeta "A A", produce: mv -i ./A A/thumb.png ../tmp/.png- todos los archivos terminan en ../tmp/.png (../tmp es mi directorio de destino).
usuario desconocido

Agregue comillas y llaves alrededor de todas las variables en el código anterior, es decir, "$ {dir}"
shellter

@ Mirror51 escribió: "archivos en algunas subcarpetas más, eso funcionará". Si deberia. ¿Sabía que puede ejecutar cada paso de este script por separado (o cuando se canalizan juntos, cada conjunto de canalizaciones)? Puede ejecutar solo el find -type dy ver la salida. ¿Obtiene eso todos los directorios que espera? Debería, si no, agregar algún resultado para mostrar el problema. Buena suerte.
shellter

No funcionará read dirrealiza la división de palabras y toma de un directorio a\nba y b como dos instancias, que ninguna máscara puede resolver.
usuario desconocido

-1

Para copiar necesita el comando cp , y cambiar el nombre de linux es lo mismo que mover el archivo, por lo que debe hacerlo con el comando mv . En Linux, siempre debe especificar la ruta completa, desde el origen, si se encuentra en otra carpeta, y hasta la carpeta de destino, por supuesto. Sería algo así, por copia:

cp /source_path/file /destination_path/

o renombrar o mover

mv /source_path/old_file /destination_path/new_name_file

Esta es solo una parte menor de la pregunta del afiche. Ahora explique cómo iterar sobre los directorios y copiar las miniaturas :-)

el OP quiere usarfind

Sí, tienes razón ... no sé lo que me pasó ...
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.