Quiere hacer archivos txt para cada png en la carpeta

12

Tengo este script

#!/bin/bash

folder='/home/data/mnist/training'

for filePng in $folder/*
do
touch $filePng.txt
done

Funciona, solo eso, para un archivo llamado 001.png, crea en 001.png.txtlugar de 001.txt.

¿Cómo puedo modificar esto?

Qubix
fuente
44
Es un buen hábito entrar para citar sus variables. El script de Shell es un lenguaje extraño que evolucionó con el tiempo en lugar de estar perfectamente diseñado desde el principio, por lo que desafortunadamente se hacen necesarias algunas cosas molestas como esta. Sin citar sus variables, los espacios en blanco o los asteriscos en el contenido de las variables harán que las cosas se rompan de manera extraña. Para hacer que sus scripts sean más robustos, siempre rodee los usos de sus variables con comillas dobles. Aquí, usted diría for filePng in "$folder"/*y touch "$filePng".txt , tenga en cuenta que solo los cita cuando está precedido por a $.
Muzer
3
Esto parece un problema XY ... ¿Por qué estás tratando de hacer esto?
JeromeJ

Respuestas:

16

Puedes usar el basenamecomando aquí:

touch "$folder/$(basename "$filePng" .png).txt"

Tenga en cuenta el adicional $folder/. Esto es necesario ya que el comando basename elimina la ruta de.

Wayne_Yux
fuente
¿Puedo sugerirle que citó la expansión de sus parámetros y la sustitución de comandos?
Tom Fenech
@TomFenech, sí, probablemente sea una buena idea citar toda la cadena. Edité mi respuesta.
Wayne_Yux
No estoy seguro de por qué eliminó las comillas internas $filePng, también fueron útiles.
Tom Fenech
1
No, porque $( )establece un nuevo contexto de citas.
Tom Fenech
2
Oh, tienes razón, aprendí algo nuevo hoy ;-)
Wayne_Yux
31

Puede eliminar la extensión existente utilizando las funciones de expansión de parámetros del shell

${parameter%pattern}El 'patrón' se compara con el final del 'parámetro'. El resultado es el valor expandido de 'parámetro' con la coincidencia más corta eliminada.

Entonces, en su caso, reemplace $filePng.txtcon"${filePng%.png}.txt"

conductor de acero
fuente
10

Con la variación de lo que Steeldriver ya mencionó (expansión de parámetros), podemos usar el reemplazo de cuerdas para hacer el trabajo. Además, debe citar variables. A continuación se muestra su guión editado.

#!/bin/bash

folder='/home/data/mnist/training'

for filePng in "$folder"/*
do
    touch "${filePng/.png/.txt}"
done
Sergiy Kolodyazhnyy
fuente
9

Si tiene muchos archivos para crear, valdría la pena "tocar" más de un archivo a la vez, de modo que no necesite bifurcar un nuevo proceso para cada uno de ellos (lo que lleva bastante tiempo si se realizan múltiples Mil veces).

Opción 1: sustitución de patrones + xargs

Esta opción proporcionará múltiples rutas al touchcomando a la vez, generalmente unos pocos miles o lo que el sistema pueda caber en una sola línea de comando.

find "$folder" -mindepth 1 -maxdepth 1 -name '*.png' -print0 |
sed -ze 's/\.png$/.txt/' |
xargs -r0 -- touch --

Opción 2: expansión de parámetros + redirección de salida de comando

Esta opción no se ejecuta touchen absoluto, sino que utiliza características de shell Bash / Bourne / POSIX que no requieren subprocesos en absoluto.

for f in "$folder"/*.png; do
    : >> "${f%.png}.txt"
done
David Foerster
fuente
4

Si está seguro de que no tiene archivos en .pngalgún lugar en el medio del nombre, puede usar una matriz con expansión de parámetros:

pngs=( /path/to/pngs/*.png )
touch "${pngs[@]/.png/.txt}"

Esto almacena todas las rutas a los archivos que terminan en .pnguna matriz y luego usa la expansión de parámetros para crear la lista de .txtarchivos, sustituyéndola .pngpor .txtcada uno.

Tenga en cuenta que esto se romperá si tiene tantos archivos que no se pueden pasar todos como argumentos a la misma invocación de touch.

Tom Fenech
fuente