¿Cómo selecciono un campo / columna de la salida de `ls -l`?

22

Mi objetivo es engañosamente simple (al menos para mí). Deseo tomar la salida de ls -lo ls -lhy seleccionar solo un campo.

Estoy buscando que esto sea lo más a prueba de balas posible, lo que quiero decir, supongo que los nombres de archivo pueden tener un número variable de espacios, no todo en el campo tiene la misma longitud, etc.

Puntos de bonificación por tener un script que tomará el nombre del campo (o incluso solo un número de campo), y luego devolverá el contenido del campo.

Quiero girar

ingrese la descripción de la imagen aquí

dentro:

ingrese la descripción de la imagen aquí

soandos
fuente

Respuestas:

41

Tratar ls -l | awk '{print $7}'.

awk selecciona columnas para que sea perfecto para esta tarea.

Corey Whitaker
fuente
3
Como lo explicó @ormaaj: No confíe en que haya información disponible en lugares específicos con ls. El findcomando es tremendamente útil.
Paddy Landau
@PaddyLandau ¿Cómo uso el comando find para imprimir un tamaño de archivo en megabytes como puedo con ls -l --block-size=M?
SurpriseDog
@Benjamin: el lscomando no es el estándar POSIX, por lo que un script que depende lspodría romperse en diferentes sistemas o incluso con el tiempo. Vea la respuesta de @ormaaj en esta página para más detalles. Una forma de hacer lo que pides es con un bucle Bash. Aquí hay un ejemplo. for FILENAME in *; do FILESIZE=$(( $( stat --format=%s "${FILENAME}" ) / 1024 )); echo "${FILENAME}" ${FILESIZE}; done. Por supuesto, en lugar de echousar su procesamiento.
Paddy Landau
@PaddyLandau Acabo de terminar canalizando la salida del comando find ... | xargs -d '\n' du -mque funciona igual de bien.
SurpriseDog
@Benjamin Es posible que desee ver la -execopción de find.
Paddy Landau
17

Nunca analizar ls . Usa GNU find. O si la portabilidad no es importante, stat(1).

find . -maxdepth 1 -printf '%Td\n'

Para leer datos que no sean listas de nombres de archivo línea por línea y dividir en campos, consulte: BashFAQ / 001

No hay métodos para leer de manera confiable una lista de nombres de archivo delimitada por una nueva línea que tenga sentido en la mayoría de las circunstancias.

ormaaj
fuente
1

Puede buscar la columna específica en shell como:

ls -al | while read perm bsize user group size month day time file; do echo $day; done

o awkcomo se muestra en la respuesta @Corey , cut -c44-45también funcionaría después del ajuste (ya que lstiene columnas fijas), o lo que sea, sin embargo, el problema principal es que no será confiable y a prueba de balas (por ejemplo, en Unix puede ser $6, no $7, y cambia según los argumentos), por lo que no es amigable para la máquina, por lols tanto , no se recomienda analizar el comando en absoluto.

Lo mejor es usar diferentes comandos disponibles como findo stat, que pueden proporcionar opciones relevantes para formatear la salida según lo necesite. Por ejemplo:

$ stat -c "%x %n" *
2016-04-10 04:53:07.000000000 +0100 001.txt
2016-04-10 05:08:42.000000000 +0100 7c1c.txt

Para devolver la columna de solo días de modificaciones, pruebe este ejemplo:

stat -c "%x" * | while read ymd; do date --date="$ymd" "+%d"; done

Vale la pena señalar que GNU statpodría tener diferentes opciones para BSD stat, por lo que aún no será a prueba de balas en diferentes sistemas operativos.

kenorb
fuente
1
+1 para mencionar que ls no debe analizarse tan bien como para su uso stat. dateSin embargo, está configurado incorrectamente. Debe agregar --date=$ymd, ya que datepor sí solo imprimirá el día actual, pero el propósito aquí es convertir el formato de fecha del archivo
Sergiy Kolodyazhnyy
El ls -la | cut -c32-33comando con total honestidad es completamente poco confiable, no solo por las posibles dificultades con los nombres de archivo, sino simplemente porque depende de la longitud de los nombres de usuario y del tamaño de los archivos. El stat -c "%x" *.*comando se ve bien, pero al usarlo *.*lo restringe solo a los nombres de archivo que contienen un punto. Supongo que la intención era capturar también archivos ocultos; en ese caso, debería permitir englobamiento de dotfiles de antemano y utilizar *en lugar de *.*: shopt -s dotglob; stat -c "%x" * | [...].
kos
Ah, y lo que dijo Serg también, debe agregarlo --date="$ymd"al datecomando, de lo contrario, imprimirá el día actual del mes.
kos
Gracias por los comentarios. Abordé los problemas y proporcioné un mejor ejemplo inicial.
kenorb