2009-06-02 5 views
34

Sé que puede hacerlo con un find, pero ¿hay alguna manera de enviar la salida de ls a mv en la línea de comandos de Unix?¿Cómo se envía la salida de ls a mv?

+0

¿Qué desea lograr? – OscarRyz

+0

Puede enviar la salida de casi cualquier comando a casi cualquier otro comando con un carácter de tubería ('|') ... pero no creo que esto sea lo que realmente desea hacer. ¿Puedes explicar lo que te gustaría lograr? –

+0

Ayudaría si describes tu problema con el comando find. – nik

Respuesta

19

Una forma es con acentos abiertos:

mv `ls *.boo` subdir 

Editar: sin embargo, esto es frágil y no recomienda - ver @ asnwer de lhunath explicaciones detalladas y recomendaciones.

+11

Que es * exactamente * el mismo que el más simple "mv * .boo subdir" * excepto * el suyo no manejará archivos con espacios en sus nombres y no funcionará si tiene "alias ls = 'ls --color = siempre '". Nunca debe confiar en la salida de ls de esta manera. –

+0

siempre podría llamar a ls directamente, es decir, whereis ls, luego '/ bin/ls' o lo que se devuelva. – PostMan

+0

Eso aún no soluciona el problema con los espacios en los nombres de archivo. –

-2

Rodeas ls con citas de la espalda y lo pone después de la MV, así como este ...

mv `ls` somewhere/ 

Pero hay que tener en cuenta que si cualquiera de los nombres de archivo tienen espacios en ellos no lo hará funciona muy bien

También sería más fácil simplemente hacer algo como esto: mv filepattern* somewhere/

5
No

exactamente seguro de lo que estamos tratando de lograr aquí, pero aquí hay una posibilidad:

La parte "xargs" es el importante pieza todo lo demás es solo configuración. El efecto de esto es tomar todo lo que "ls" produce y agregarle una extensión ".txt".

 
$ 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 
$ 

Algo como esto también podría lograrse mediante:

 
$ 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 
$ 

que algo así como el segundo mejor manera. NUNCA puedo recordar cómo xargs funciona sin leer la página de manual o ir a mi archivo de "trucos lindos".

Espero que esto ayude.

+0

@kungfugraig: tenga en cuenta que las observaciones de @David Williamson sobre los nombres de archivo que contienen espacios también se aplican al uso de xargs. –

+3

No es necesario que los 'ls' -" for i in *; do whatever; done "funcionen también. –

5

Consulte find -exec {} ya que podría ser una mejor opción que ls, pero depende de lo que esté tratando de lograr.

+4

Debe dar un ejemplo, como "buscar". -name '* .txt' -exec cp '{}'/stuff ';' ". Especialmente porque no es obvio que las citas sean correctas. –

+0

Como dijo jleedev entonces. – sybreon

0

Backticks funcionan bien, como otros han sugerido. Ver xargs, también. Y para cosas realmente complicadas, póngalo en sed, haga la lista de comandos que desee, luego ejecútelo de nuevo con la salida de sed en sh.

He aquí un ejemplo con el hallazgo, pero funciona bien con ls, también:

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

+0

Votos descendentes? ¿Seriamente? :(Reconocí las otras buenas respuestas, y dí un par de enfoques adicionales que funcionan en situaciones donde los backticks no. –

2

No use la salida de ls como entrada de otro comando. Los archivos con espacios en sus nombres son difíciles como es la inclusión de secuencias de escape ANSI si tiene:

alias ls-'ls --color=always' 

por ejemplo.

Siempre use find o xargs (con -0) o globbing.

Además, no indicó si desea mover archivos o cambiarles el nombre. Cada uno se manejaría de manera diferente.

edición: -0 añadido a xargs (gracias por el recordatorio)

+0

xargs también tiene problemas con los espacios en los nombres (a menos que sea alimentado, digamos, por un resultado -print0, y ejecutar con un -0 en sí). –

+0

... que siempre debe existir, existe el riesgo de que las rutas tengan espacios en blanco en ellos – JesperE

+0

además xargs también intenta comer caracteres de comillas contenidos en sus nombres de archivo si no se ejecutó con la opción -0 Le recomiendo que elimine xargs de la respuesta o agregue que -0 es una necesidad absoluta. – lhunath

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

"uso inútil de ls", pero debería funcionar. Al especificar la ruta completa a ls (1), evita los conflictos con el aliasing de ls (1) mencionado en algunas de las publicaciones anteriores. El comando tr (1) junto con "xargs -0" hace que el comando funcione con nombres de archivo que contienen (ugh) espacios en blanco. No funcionará con nombres de archivos que contengan líneas nuevas, pero tener nombres de archivos como ese en el sistema de archivos es para buscar problemas, por lo que probablemente no será un gran problema. Sin embargo, los nombres de archivo con las nuevas líneas podrían existir, por lo que una solución mejor sería utilizar "encontrar -print0":

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

Los nombres de archivo pueden contener líneas nuevas. – lhunath

-1
#!/bin/bash 

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

demás, es la solución hallazgo por sybreon, y como se sugiere no la solución ls mv verde.

67

ls es una herramienta que se utiliza para VISUALIZAR algunas estadísticas sobre nombres de archivos en un directorio.

Es no herramienta que debe usar para enumerarlas y pasarlas a otra herramienta para usarla allí. El análisis de ls es casi siempre lo que no debe hacerse, y se interrumpe de muchas maneras.

Para un documento detallado sobre la maldad de ls análisis sintáctico, que debe realmente ir a leer, echa un vistazo a: http://mywiki.wooledge.org/ParsingLs

su lugar, debe utilizar cualquiera de pegotes o encontrar, dependiendo de qué es exactamente lo que está tratando de lograr:

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

La principal fuente de maldad de análisis ls es que ls vertederos de todos los nombres de archivo en una sola cadena de la producción, y no hay manera de Dile los nombres de los archivos aparte de allí. ¡Para todo lo que sabe, la salida completa de ls podría ser un único nombre de archivo!

La fuente secundaria de maldad del análisis ls proviene de la forma rota en que medio mundo utiliza bash. Ellos piensan for mágicamente hace lo que les gustaría hacer cuando hacen algo como:

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

for es una fiesta de orden interna que itera sobre argumentos. Y $(ls) toma la salida de ls y la divide en argumentos dondequiera que haya spaces, newlines o tabs. Lo que básicamente significa que está iterando sobre palabras, no sobre nombres de archivo. Lo que es peor, está pidiendo tomar basto para tomar cada una de esas palabras de nombre de archivo mutilado y luego tratarlas como comodines que pueden coincidir con nombres de archivo en el directorio actual. Entonces, si tiene un nombre de archivo que contiene una palabra que resulta ser un comodín que coincide con otros nombres de archivo en el directorio actual, esa palabra desaparecerá y todos los nombres de archivo coincidentes aparecerán en su lugar.

mv `ls` /foo  # Exact same badness as the ''for'' thing. 
+0

'find. -exec mv {}/foo \;', ¿qué significa '{}' aquí? ¿Hay algún momento en que coloquemos algo dentro de '{}'? –

+0

En mi máquina, 'man find | grep {}' dice que: Un parámetro de comando {} (llaves) se reemplaza por el nombre de la ruta actual. – stevepastelan

+0

@Than gPham {} es donde find coloca el nombre de archivo actual. Nunca colocas nada dentro del {} y siempre debe estar parado como un argumento en sí mismo (es decir, nunca "dentro" de un argumento como "{} .txt". – lhunath

4

Ninguna de las respuestas hasta ahora es segura para los nombres de archivos con espacios en ellas.Prueba esto:

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

Por supuesto, puede utilizar cualquier patrón global que desea en lugar de *.

+0

esta es la esencia de bash. –

0

Solo use find o sus proyectiles globing!

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

..o ..

mv * /tmp/blah/ 

Usted no tiene que preocuparse de color en la salida de ls, u otro extraño tuberías - Linux permite, básicamente, cualquier carácter en el nombre del archivo, excepto un byte nulo .. Por ejemplo:

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

..pero encuentran funciona perfectamente:

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

Para casos más complicados (a menudo en una secuencia de comandos), el uso de arrays bash para construir la lista de argumentos puede ser muy útil. Uno puede crear una matriz e impulsarla con la lógica condicional apropiada. Por ejemplo:

seguimiento a @ lhunath de recommendation utilizar globos o encontrar, impulsar los archivos que coinciden con un patrón global de la matriz:

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

archivos que coinciden con un empuje encuentran a la matriz: https://stackoverflow.com/a/23357277/430128.

Añadir argumentos adicionales como sea necesario:

myargs+=("Some directory") 

Uso myargs en la invocación de un comando como mv:

mv "${myargs[@]}" 

Nota de la cita de la matriz myargs para pasar correctamente elementos de la matriz con espacios.

Cuestiones relacionadas