¿Cómo hago para que el shell reconozca los nombres de archivo devueltos por un comando 'ls -A', y estos nombres contienen espacios?

3

Esta es la parte de la secuencia de comandos que estoy usando para cambiar el nombre de los archivos devueltos por ls -A :

for FILE in 'ls -A'
do
        ext=${FILE##*.}
        NUM=$(($NUM+1))
        NEWFILE='echo _$NUM.$ext | sed 's/ /_/g''

        mv "$FILE" "$NEWFILE"
done

¡Pero no puede encontrar nombres con espacio! El parámetro de $ 2 no puede ser la causa del error por el que alguna vez paso un nombre sin un espacio como parámetro, y este script toma ese nombre y renombra todos los archivos en la carpeta para dejarlos numerados y no modifica la extensión del archivo. Lamentablemente, no cambia el nombre de los archivos con espacios en el nombre. ¿Alguien puede ayudarme?

    
pregunta Patterson 14.03.2014 - 12:59

5 respuestas

2

ls -A para mí escribe múltiples nombres de archivo en una línea, separados por espacios en blanco. Si intentas agregar -1 como ls -A1 que generará un nombre de archivo por línea, y podría funcionar mejor para ti.

Me he encontrado con los mismos problemas con espacios en nombre de archivo, especialmente cuando uso find, pero separar nombres con un carácter nulo maneja espacios & amp; nuevas líneas en los nombres de archivo:
find (...) -print0 | xargs -0 (do stuff here)

Pero, si solo quieres cambiar el nombre de los archivos, puedes considerar man rename que puede hacer cosas como:

For example, to rename all files matching "*.bak" to strip the extension,
you might say
     rename 's/\.bak$//' *.bak
To translate uppercase names to lower, you'd use
     rename 'y/A-Z/a-z/' *

O para una solución gui para algunos directorios, Thunar tiene una bonita interfaz Rename Multiple Files que también puede numerar cómo se está describiendo. Acabo de probar algunos nombres de archivo con espacios combinados con find to Thunar y parece funcionar:
find . -type f -print0 | xargs -0 thunar -B

    
respondido por el Xen2050 14.03.2014 - 14:05
9

for itera sobre palabras , las palabras están delimitadas por espacios en blanco. No debe iterar sobre la salida de ls , debe usar * .* :

for file in * .* ; do
    if [[ $file = . || $file = .. ]] ; then
        continue
    fi
    # ...
done
    
respondido por el choroba 14.03.2014 - 13:27
6

Puede incluir archivos ocultos ('archivos de puntos') en el glob de shell bash '*' configurando la opción de shell dotglob

shopt -s dotglob
for file in *
do 
  echo "$file"
done

por ej. para un directorio que contiene file , file with spaces y .hidden file (el último de los cuales está oculto y tiene un espacio) esto produce

file
file with spaces
.hidden file

También puede agregar la opción nullglob para evitar una condición de error en el caso de que el directorio esté vacío; consulte la excelente BashFAQ / 004 . Recuerde citar la variable "$file" y también es una buena práctica no usar mayúsculas para sus nombres de variable.

    
respondido por el steeldriver 14.03.2014 - 14:05
1

En caso de que aún no lo hayas descifrado, analizar ls es Bad Idea ® . A menos que sepa que sus nombres de archivo estarán siempre sanos (normalmente no puede), debe ser capaz de tratar con nombres de archivos que contengan:

  • espacios y pestañas
  • espacios o pestañas consecutivos
  • nuevas líneas ( \n )
  • retorno de carro ( \r )
  • barras diagonales inversas ( \ )

Todo lo anterior está permitido por el kernel de Linux (y están garantizados para conducir su administrador de sistemas loco). Los siguientes dos métodos pueden tratar con cualquier combinación de los anteriores. Estoy usando cp file directory/ como un comando de ejemplo):

  1. Usar find y su opción -exec , el {} será reemplazado por cada archivo o directorio encontrado.

    find . -exec cp {} directory/
    
  2. Resultados de búsqueda de pts a xargs como cadenas separadas nulas ( -print0 ), indica a xargs que lea nulo separado ( -0 ) y dile que reemplace {} con cada nombre de archivo / directorio ( -I {} ).

    find . -print0 | xargs -0 -I {} cp {} directory/
    
  3. Usa solo el intérprete de comandos para hacer coincidir los archivos de puntos, activa dotglob

     shopt -s dotglob
     for i in *; do cp -v "$i" directory/; done
    
  4. Combina la potencia de find y la versatilidad del caparazón

    find . -print0 | while IFS= read -r -d '' i; do cp "$i" directory/; done
    

    El IFS= deshabilita la división en espacios, el -r deshabilita los escapes de la barra invertida (permite que las barras invertidas sean tratadas literalmente), el -d '' establece el separador de registros (líneas si lo desea) en nulo.

respondido por el terdon 15.03.2014 - 05:01
0

Qué tal:

ls -A | while read fname
do
    echo "$fname" # your code goes here
done

Tubería ls lo obliga a enviar 1 nombre de archivo por línea, read luego acepta la línea en la variable fname .

    
respondido por el efwolcott 14.03.2014 - 19:46