Nunca, nunca lo usesfor foo in $(cat bar)
. Este es un error clásico, comúnmente conocido como bash pitfall number 1 . En su lugar, debe usar:
while IFS= read -r file; do mv -- "$file" "new_place/$file"; done < file_list.txt
Cuando se ejecuta el for
bucle, golpe del aplicará wordsplitting a lo que lee, lo que significa que a strange blue cloud
se puede leer como a
, strange
, blue
y cloud
:
$ cat files
a strange blue cloud.txt
$ for file in $(cat files); do echo "$file"; done
a
strange
blue
cloud.txt
Comparar con:
$ while IFS= read -r file; do echo "$file"; done < files
a strange blue cloud.txt
O incluso, si insiste en la UUoC :
$ cat files | while IFS= read -r file; do echo "$file"; done
a strange blue cloud.txt
Entonces, el while
ciclo leerá su entrada y usará read
para asignar cada línea a una variable. Los IFS=
conjuntos El separador de campo de entrada a NULL * , y de la -r
opción de read
paradas de TI de la interpretación de escapes de barra invertida (de modo que \t
se trata como barra + t
y no como una pestaña). El --
después de que el mv
medio "tratar todo después de que el - como un argumento y no es una opción", que le permite hacer frente a los nombres de archivo que comienzan con -
correctamente.
* Esto no es necesario aquí, estrictamente hablando, el único beneficio en este escenario es que evita read
eliminar cualquier espacio en blanco al inicio o al final, pero es un buen hábito a tener en cuenta cuando necesita tratar con nombres de archivos que contienen caracteres de nueva línea, o en general, cuando necesita poder tratar con nombres de archivos arbitrarios.
IFS=
no ayudará con las nuevas líneas en los nombres de archivo. El formato del archivo aquí simplemente no permite nombres de archivo con nuevas líneas.IFS=
es necesario para los nombres de archivos que comienzan en el espacio o en la pestaña (o cualquier otro carácter que no sea el de nueva línea $ IFS contenido de antemano).ls
ofind
con sustituciones de comandos cuando hay formas mejores y más confiables de hacerlo.$(cat file)
estaría bien cuando se hace bien. Es tan difícil "hacerlo bien" con un ciclo de lectura while como con un + $ (...). Mira mi respuesta.Que
$(cat file_list.txt)
en los shells POSIX comobash
en el contexto de la lista es el operador split + glob (zsh
solo hace la parte dividida como cabría esperar).Se divide en caracteres de
$IFS
(de forma predeterminada, SPC , TAB y NL) y se globaliza a menos que desactive el globbing por completo.Aquí, desea dividir solo en nueva línea y no desea la parte global, por lo que debería ser:
Eso también tiene la ventaja (sobre un
while read
bucle) de descartar líneas vacías, preservar una línea final no terminada y preservarmv
la entrada estándar (necesaria en caso de avisos, por ejemplo).Sin embargo, tiene la desventaja de que el contenido completo del archivo debe almacenarse en la memoria (varias veces con shells como
bash
yzsh
).Con algunos shells ( y
ksh
,zsh
en menor medidabash
), puede optimizarlo en$(<file_list.txt)
lugar de hacerlo$(cat file_list.txt)
.Para hacer el equivalente con un
while read
bucle, necesitarías:O con
bash
:O con
zsh
:O con GNU
mv
yzsh
:O con GNU
mv
y GNUxargs
y ksh / zsh / bash:Más información sobre lo que significa dejar las expansiones sin citar en Implicaciones de seguridad al olvidar citar una variable en bash / POSIX shells
fuente
$(cat file_list.txt)
lee todo el archivo en la memoria antes de iterar, mientras quewhile read ...
solo lee una línea a la vez. Esto podría ser un problema para archivos grandes.En lugar de escribir un guión, puede usar find ..
para el caso en que los archivos se encuentran en el archivo, puede hacer lo siguiente:
el segundo no estoy seguro ..
Buena suerte
fuente
find
, también puede usarlofind
para todo. ¿Por qué traerloxargs
?find -type f -iname '*.txt' -exec mv {} /folder/to/destination/
.-exec
se comporta perfectamente con nombres de archivo arbitrarios (incluidos los que contienen espacios, líneas nuevas o cualquier otra rareza). Sé cómoxargs
funciona, gracias :) Simplemente no veo el punto de llamar a un comando separado cuandofind
ya puedo hacerlo por ti. No tiene nada de malo, simplemente ineficiente.xargs
también tiene el inconveniente de golpear stdin (quemv
necesita para sus indicaciones). También un problema con la solución de @terdon. Con GNUxargs
y conchas con sustitución de procesos, se puede aliviar conxargs -0IF -a <(find...) mv F /dest
#! / bin / bash
ARCHIVO =
zenity --title "Pick a Movie" --file-selection
para ARCHIVO en "$ {ARCHIVO [0]}"
hacer omxplayer "$ {FILE [0]}" hecho
! / bin / bash
ARCHIVO =
zenity --title "Pick a Song" --file-selection
para ARCHIVO en "$ {ARCHIVO [0]}"
jugar "$ {FILE [0]}" hecho
! / bin / bash
DIR =
zenity --title "Pick a Album" --file-selection --directory
para DIR en "$ {DIR [0]}"
haga el cd "$ {DIR [0]}" && find. -type f -name ' .ogg' -o -name ' .mp3' | sort --version-sort | mientras lee DIR; jugar "$ DIR" hecho hecho
! / bin / bash
DIR =
zenity --title "Pick a Album" --file-selection --directory
para DIR en "$ {DIR [0]}"
haga el cd "$ {DIR [0]}" && find. -type f -name ' .ogg' -o -name ' .mp3' | mientras lee DIR; jugar "$ DIR" hecho hecho
fuente