Qualcuno ha uno script di shell modello per fare qualcosa con lsun elenco di nomi di directory e scorrere in ciascuno di essi e fare qualcosa?
Sto programmando di fare ls -1d */per ottenere l'elenco dei nomi delle directory.
Qualcuno ha uno script di shell modello per fare qualcosa con lsun elenco di nomi di directory e scorrere in ciascuno di essi e fare qualcosa?
Sto programmando di fare ls -1d */per ottenere l'elenco dei nomi delle directory.
Risposte:
Modificato per non usare ls dove farebbe un glob, come suggerito da @ shawn-j-goff e altri.
Basta usare un for..do..doneloop:
for f in *; do
echo "File -> $f"
done
È possibile sostituire il *con *.txto qualsiasi altro glob che restituisce un elenco (di file, directory o qualsiasi altra cosa), un comando che genera un elenco, ad esempio $(cat filelist.txt), o sostituirlo effettivamente con un elenco.
All'interno del dociclo, fai semplicemente riferimento alla variabile del ciclo con il prefisso del simbolo del dollaro (quindi $fnell'esempio sopra). Puoi echofarlo o fare qualsiasi altra cosa tu voglia.
Ad esempio, per rinominare tutti i .xmlfile nella directory corrente in .txt:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
O ancora meglio, se stai usando Bash puoi usare le espansioni dei parametri di Bash invece di generare una subshell:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
forloop e una trappola tipica del tentativo di analizzare l'output di ls. @ DanielA.Bianco, potresti considerare di non accettare questa risposta se non è stata utile (o è potenzialmente fuorviante), dal momento che come hai detto, stai agendo su directory. La risposta di Shawn J. Goff dovrebbe fornire una soluzione più solida e funzionante al tuo problema.
lsoutput , non dovresti leggere l'output in un forciclo , dovresti usare $()invece di `` and Use More Quotes ™ . Sono sicuro che @CoverosGene intendesse bene, ma è terribile.
lsè ls -1 | while read line; do stuff; done. Almeno quello non si romperà per gli spazi bianchi.
mv -vte non serveecho "moved $x -> $t"
Usare l'output di lsper ottenere nomi di file è una cattiva idea . Può portare a malfunzionamenti e persino a script pericolosi. Questo perché un nome di file può contenere qualsiasi carattere tranne /ed il nullcarattere, e lsnon utilizzare uno dei quei caratteri come delimitatori, quindi se un nome di file ha uno spazio o un ritorno a capo, si sarà ottenere risultati inaspettati.
Esistono due modi molto efficaci per scorrere i file. Qui, ho usato semplicemente echoper dimostrare di fare qualcosa con il nome file; puoi usare qualsiasi cosa, però.
Il primo consiste nell'utilizzare le funzionalità di globbing native della shell.
for dir in */; do
echo "$dir"
done
La shell si espande */in argomenti separati che il forciclo legge; anche se c'è uno spazio, una nuova riga o qualsiasi altro carattere strano nel nome del file, forvedrà ogni nome completo come un'unità atomica; non sta analizzando l'elenco in alcun modo.
Se si vuole andare in modo ricorsivo in sottodirectory, allora questo non farà a meno che il guscio ha alcune caratteristiche globbing estese (ad esempio bash's globstar. Se la shell non ha queste caratteristiche, o se si vuole garantire che lo script funziona su una varietà di sistemi, quindi l'opzione successiva è usare find.
find . -type d -exec echo '{}' \;
Qui, il findcomando chiamerà echoe gli passerà un argomento del nome file. Lo fa una volta per ogni file che trova. Come nell'esempio precedente, non è possibile analizzare un elenco di nomi di file; invece, un fileneame viene inviato completamente come argomento.
La sintassi -execdell'argomento sembra un po 'divertente. findprende il primo argomento dopo -exece lo considera come programma da eseguire, e ogni argomento successivo, serve come argomento per passare a quel programma. Ci sono due argomenti speciali che -execdevono essere visti. Il primo è {}; questo argomento viene sostituito con un nome file findgenerato dalle parti precedenti . Il secondo è ;, che fa findsapere che questa è la fine della lista di argomenti da passare al programma; findne ha bisogno perché puoi continuare con più argomenti che sono previsti finde non destinati al programma exec'd. Il motivo \è che anche la shell tratta;specialmente - rappresenta la fine di un comando, quindi dobbiamo evitarlo in modo che la shell lo dia come argomento findpiuttosto che consumarlo per se stesso; un altro modo per far sì che la shell non la tratti in modo particolare è inserirla tra virgolette: ';'funziona altrettanto bene sia \;per questo scopo.
find. C'è della magia che può essere fatta e persino i limiti percepiti di -execpossono essere aggirati. L' -print0opzione è anche utile per l'uso con xargs.
Per i file con spazi all'interno devi assicurarti di citare la variabile come:
for i in $(ls); do echo "$i"; done;
oppure, è possibile modificare la variabile di ambiente IFS (input field separator):
IFS=$'\n';for file in $(ls); do echo $i; done
Infine, a seconda di cosa stai facendo, potresti non aver nemmeno bisogno di ls:
for i in *; do echo "$i"; done;
\nè insufficiente. Non è mai una buona idea raccomandare di analizzare l'output di ls.
Se hai installato GNU Parallel http://www.gnu.org/software/parallel/ puoi farlo:
ls | parallel echo {} is in this dir
Per rinominare tutto .txt in .xml:
ls *.txt | parallel mv {} {.}.xml
Guarda il video introduttivo di GNU Parallel per saperne di più: http://www.youtube.com/watch?v=OpaiGYxkSuQ
Perché non impostare IFS su una nuova riga, quindi acquisire l'output di lsin un array? L'impostazione di IFS su newline dovrebbe risolvere i problemi con caratteri divertenti nei nomi dei file; l'utilizzo lspuò essere utile perché ha una funzione di ordinamento integrata.
(Durante i test ho riscontrato difficoltà nell'impostare IFS \nma l'impostazione su backline di nuova riga funziona, come suggerito altrove qui):
Ad esempio (supponendo che il lsmodello di ricerca desiderato sia passato $1):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
Ciò è particolarmente utile su OS X, ad esempio per acquisire un elenco di file ordinati per data di creazione (dalla più vecchia alla più recente), il lscomando è ls -t -U -r.
\nè insufficiente. Le uniche soluzioni valide utilizzano un ciclo for con espansione del percorso o find.
È così che lo faccio, ma probabilmente ci sono modi più efficienti.
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done