Vuoi creare file txt per ogni png nella cartella


12

Ho questa sceneggiatura

#!/bin/bash

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

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

Funziona, solo che, per un file chiamato 001.png, crea 001.png.txtinvece di 001.txt.

Come posso modificarlo?


4
È una buona abitudine entrare per citare le tue variabili. Lo script della shell è un linguaggio strano che si è evoluto nel tempo piuttosto che essere perfettamente progettato fin dall'inizio, quindi purtroppo alcune cose fastidiose come questa diventano necessarie. Senza citare le variabili, spazi bianchi o asterischi nei contenuti delle variabili causano la rottura delle cose in modi strani. Per rendere i tuoi script più robusti, circonda sempre gli usi delle variabili con virgolette doppie. Qui diresti for filePng in "$folder"/*e touch "$filePng".txt - nota che li citi solo quando preceduto da a $.
Muzer,

3
Sembra un problema XY ... Perché stai cercando di farlo?
JeromeJ,

Risposte:


16

Puoi usare il basenamecomando qui:

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

Nota l'ulteriore $folder/. Questo è necessario poiché il comando basename rimuove il percorso da.


Potrei suggerire di aver citato l'espansione dei parametri e la sostituzione dei comandi?
Tom Fenech,

@TomFenech sì, probabilmente una buona idea per citare l'intera stringa. Ho modificato la mia risposta.
Wayne_Yux,

Non sono sicuro del motivo per cui hai rimosso le virgolette interne $filePng: erano anche utili.
Tom Fenech,

1
No, perché $( )stabilisce un nuovo contesto di quotazione.
Tom Fenech,

2
Oh, hai ragione
ho

31

È possibile rimuovere l'estensione esistente utilizzando le funzionalità di espansione dei parametri della shell

${parameter%pattern}Il "modello" è abbinato alla fine del "parametro". Il risultato è il valore espanso di "parametro" con la corrispondenza più breve eliminata.

Quindi, nel tuo caso, sostituiscilo $filePng.txtcon"${filePng%.png}.txt"


10

Con la variazione di quanto già detto steeldriver - espansione dei parametri - possiamo usare la sostituzione di stringhe per fare il lavoro. Inoltre, dovresti citare le variabili. Di seguito è riportato il tuo script modificato.

#!/bin/bash

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

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

9

Se hai molti file da creare, varrebbe la pena "toccare" più di un file alla volta, quindi non è necessario eseguire il fork di un nuovo processo per ciascuno di essi (che richiede parecchio tempo se eseguito in più mille volte).

Opzione 1: sostituzione del modello + xargs

Questa opzione fornirà più percorsi al touchcomando contemporaneamente, di solito qualche migliaio o qualunque cosa il sistema possa adattare su una singola riga di comando.

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

Opzione 2: espansione parametri + reindirizzamento output comando

Questa opzione non funziona touchaffatto ma utilizza invece le funzionalità della shell Bash / Bourne / POSIX che non richiedono affatto processi secondari.

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

4

Se sei sicuro di non avere file con .pngqualcosa nel mezzo del nome, puoi semplicemente usare un array con espansione dei parametri:

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

Questo memorizza tutti i percorsi dei file che finiscono in .pngun array e quindi utilizza l'espansione dei parametri per creare l'elenco di .txtfile, sostituendo .pngper .txtognuno.

Tieni presente che questo si interromperà se hai così tanti file che non possono essere passati tutti come argomenti alla stessa invocazione di touch.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.