¿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.

Espejismo
fuente
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.

Simón
fuente
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.

lesmana
fuente
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.

usuario desconocido
fuente
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.

shellter
fuente
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

fuente
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ó ...