2009-06-02 15 views
34

So che puoi farlo con un find, ma c'è un modo per inviare l'output di ls a mv nella riga di comando di Unix?Come si invia l'output di ls a mv?

+0

Cosa vuoi raggiungere? – OscarRyz

+0

È possibile inviare l'output di quasi tutti i comandi a quasi tutti gli altri comandi con un carattere pipe ('|') ... ma non penso che questo sia ciò che si vuole veramente fare. Puoi spiegare cosa vorresti realizzare? –

+0

Sarebbe utile se descrivete il vostro problema con il comando find. – nik

risposta

19

Un modo è quello con apici inversi:

mv `ls *.boo` subdir 

Edit: tuttavia, questo è fragile e non raccomandato - vedere @ asnwer di lhunath per spiegazioni dettagliate e raccomandazioni.

+11

Che è * esattamente * uguale al più semplice "mv * .boo sottodir" * eccetto * il tuo non gestirà i file con spazi nei loro nomi e non funzionerà se hai "alias ls = 'ls --color = sempre". Non dovresti mai fare affidamento sull'output di ls in questo modo. –

+0

potrebbe sempre chiamare ls direttamente, cioè dove è ls, quindi '/ bin/ls' o qualsiasi altra cosa viene restituita. – PostMan

+0

Che ancora non risolve il problema con gli spazi nei nomi dei file. –

-2

circondano il ls con le citazioni della schiena e metterlo dopo la MV, così come questo ...

mv `ls` somewhere/ 

ma di tenere presente che se uno dei tuoi nomi di file sono spazi tra loro non lo farà funziona molto bene

Inoltre sarebbe più semplice di fare proprio qualcosa di simile: mv filepattern* somewhere/

5
Non

esattamente sicuro di quello che stai cercando di ottenere qui, ma qui è una possibilità:

La parte "xargs" è l'importante pezzo tutto il resto è solo l'installazione. L'effetto di questo è prendere tutto ciò che "ls" produce e aggiungere un'estensione ".txt" ad esso.

 
$ mkdir xxx # 
$ cd xxx 
$ touch a b c x y z 
$ ls 
a b c x y z 
$ ls | xargs -Ifile mv file file.txt 
$ ls 
a.txt b.txt c.txt x.txt y.txt z.txt 
$ 

Qualcosa di simile potrebbe anche essere ottenuto:

 
$ touch a b c x y z 
$ for i in `ls`;do mv $i ${i}.txt; done 
$ ls 
a.txt b.txt c.txt x.txt y.txt z.txt 
$ 

ho un po 'come il secondo modo migliore. Non posso MAI ricordare come xargs funziona senza leggere la pagina man o andare al mio file "trucchi carini".

Spero che questo aiuti.

+0

@kungfugraig: nota che le osservazioni di @David Williamson sui nomi di file contenenti spazi si applicano anche al tuo uso di xargs. –

+3

Non c'è alcun particolare bisogno di 'ls' -" for i in *; do any; done "funziona anche. –

5

Check out find -exec {} come potrebbe essere una soluzione migliore di ls ma dipende da ciò che stai cercando di raggiungere.

+4

Dovresti fare un esempio, come "trova". -name '* .txt' -exec cp '{}'/stuff ';' ". Soprattutto perché non è ovvio che la quotazione sia corretta. –

+0

Come disse allora Jleedev. – sybreon

0

I backtick funzionano bene, come altri hanno suggerito. Vedi anche xargs. E per cose davvero complicate, inseriscile in sed, fai la lista dei comandi che vuoi, quindi eseguila di nuovo con l'output di sed pipe in sh.

Ecco un esempio con find, ma funziona bene con ls, troppo:

http://github.com/DonBranson/scripts/blob/f09d24629ab6eb3ce509d4d3078818430306b063/jarfinder.sh

+0

Downvotes? Sul serio? :(Ho riconosciuto le altre buone risposte e ho dato un paio di approcci aggiuntivi che funzionano in situazioni in cui i backtick non lo sono. –

2

Si consiglia di non utilizzare l'uscita di ls come input di un altro comando. I file con gli spazi nei loro nomi sono difficili così come l'inserimento di sequenze di escape ANSI se si dispone di:

alias ls-'ls --color=always' 

per esempio.

Usa sempre find o xargs (con -0) o globbing.

Inoltre, non hai detto se vuoi spostare i file o rinominarli. Ognuno sarebbe gestito diversamente.

Edit: aggiunte -0 a xargs (grazie per il promemoria)

+0

xargs ha problemi con gli spazi nei nomi (a meno che non sia alimentato, per esempio, da un find -print0, ed esegui con a -0 stesso.) –

+0

... che dovrebbe sempre esserci, c'è il rischio che i percorsi abbiano spazi bianchi in loro – JesperE

+0

inoltre xargs prova anche a mangiare i caratteri di citazione contenuti nei nomi dei file se non è stato eseguito con l'opzione -0 Ti consiglio di rimuovere xargs dalla risposta o di aggiungere che -0 è un assoluto. – lhunath

0
/bin/ls | tr '\n' '\0' | xargs -0 -i% mv % /path/to/destdir/ 

"uso inutile di ls", ma dovrebbe funzionare. Specificando il percorso completo di ls (1) eviti gli scontri con l'aliasing di ls (1) menzionato in alcuni dei post precedenti. Il comando tr (1) insieme a "xargs -0" fa funzionare il comando con nomi di file contenenti spazi (ugh). Non funzionerà con nomi di file contenenti newline, ma avere nomi di file del genere nel file system è chiedere un problema, quindi probabilmente non sarà un grosso problema. Ma i nomi dei file con a capo potrebbero esistere, quindi una soluzione migliore sarebbe quella di utilizzare "trova -print0":

find /path/to/srcdir -type f -print0 | xargs -0 -i% mv % dest/ 
+0

I nomi dei file possono contenere newline. – lhunath

-1
#!/bin/bash 

for i in $(ls *); 
do 
mv $1 /backup/$1 
done 

altro, è la soluzione ritrovamento da sybreon, e come suggerito non la soluzione ls mv verde.

67

ls è uno strumento utilizzato per VISUALIZZARE alcune statistiche sui nomi di file in una directory.

È non uno strumento da utilizzare per enumerarli e passarli a un altro strumento per utilizzarlo lì. L'analisi ls è quasi sempre la cosa sbagliata da fare e viene intercettata in molti modi.

Per un documento dettagliato sulla cattiveria di ls parsing, che si dovrebbe davvero andare a leggere, check out: http://mywiki.wooledge.org/ParsingLs

Invece, si dovrebbe usare sia gocce o trovare, a seconda di cosa esattamente si sta cercando di raggiungere:

mv * /foo 
find . -exec mv {} /foo \; 

La fonte principale di malizia delle analisi ls è che ls discariche tutti i nomi di file in una singola stringa di uscita, e non v'è alcun modo per dì i nomi dei file a parte da lì. Per quel che ne sai, l'intero output di ls potrebbe essere un singolo nome di file!

La fonte secondaria di parassita di parsing ls deriva dal modo spezzato in cui mezzo mondo usa bash. Pensano for magicamente fa quello che vorrebbero per fare quando fanno qualcosa di simile:

for file in `ls` # Never do this! 
for file in $(ls) # Exactly the same thing. 

for è un builtin Bash che itera su argomenti. E $(ls) prende l'output di ls e lo divide in argomenti ovunque ci sia spaces, newlines o tabs. Che in pratica significa che stai iterando su parole, non oltre nomi di file. Ancor peggio, stai chiedendo a bask di prendere ognuna di quelle parole di nome file mutilate e quindi trattarle come globi che potrebbero corrispondere ai nomi di file nella directory corrente. Quindi se hai un nome di file che contiene una parola che sembra essere un glob che corrisponde ad altri nomi di file nella directory corrente, quella parola scompare e tutti quei nomi di file corrispondenti appariranno al suo posto!

+0

'find. -exec mv {}/foo \;', cosa significa '{}' qui? C'è un momento in cui mettiamo qualcosa dentro '{}'? –

+0

Sulla mia macchina, 'man find | grep {}' dice che: Un parametro di comando {} (parentesi) viene sostituito dal nome del percorso corrente. – stevepastelan

+0

@Than gPham {} è dove find inserisce il nome file corrente. Non mettete mai nulla dentro {} e dovrebbe sempre essere in piedi da solo come argomento (cioè mai "dentro" un argomento come "{} .txt". – lhunath

4

Nessuna delle risposte finora è sicura per i nomi di file con spazi al loro interno.Prova questo:

for i in *; do mv "$i" some_dir/; done 

È possibile utilizzare naturalmente qualsiasi modello glob che ti piace al posto di *.

+0

questa è l'essenza di bash. –

0

Basta usare find o il tuo globing di shell!

find . -depth=1 -exec mv {} /tmp/blah/ \; 

..o ..

mv * /tmp/blah/ 

Non dovete preoccuparvi di colore nell'output ls, o altre stranezze tubazioni - Linux permette in sostanza tutti i caratteri nel nome del file, tranne un byte null .. Per esempio:

$ touch "blah\new| 
> " 
$ ls | xargs file 
blahnew|:     cannot open `blahnew|' (No such file or directory) 

..ma Trova opere perfettamente:

$ find . -exec file {} \; 
./blah\new| 
: empty 
0

Per i casi più complicati (spesso in uno script), utilizzare gli array di bash per creare l'elenco degli argomenti può essere molto utile. Si può creare un array e spingerlo con la logica condizionale appropriata. Per esempio:

Facendo seguito a @ lhunath di recommendation di utilizzare gocce o trovare, spingere i file che corrispondono a un modello di glob alla matrice:

myargs=() 
# don't push if the glob does not match anything 
shopt -s nullglob 
myargs+=(myfiles*) 

file push corrispondenti a find alla matrice: https://stackoverflow.com/a/23357277/430128.

Aggiungere argomenti aggiuntivi come necessario:

myargs+=("Some directory") 

Uso myargs nell'invocazione di un comando come mv:

mv "${myargs[@]}" 

Nota la citazione della matrice myargs passare correttamente elementi dell'array con spazi.