Cómo ordenar los primeros directorios, luego los archivos, etc. ... cuando se usa "ls" en Unix

91

Me gustaría usar el lscomando para mostrar primero los directorios y luego los archivos. Lo intenté:

ls -la | sort -k 1

Pero recibí un orden equivocado.

atricapilla
fuente
es porque -viene antes dcuando se usasort
Nifle
44
Los cabezales de Unix de antaño (los de la era anterior a la GUI) solían poner en mayúscula los nombres de sus carpetas y hacer que los nombres de archivos sin formato se capitalizaran para obtener ese resultado automáticamente.
JRobert
Pregunta útil! ¿Quizás es hora de cambiar la respuesta aceptada por una más simple y que no rompa los colores terminales?
ippi
Pruebals -lh --group-directories-first
Diogo

Respuestas:

28

El siguiente comando enumerará los directorios primero, los archivos ordinarios en segundo lugar y los enlaces en tercer lugar.

ls -la | grep "^d" && ls -la | grep "^-" && ls -la | grep "^l"

Además, tendría mucho sentido crear un alias para este comando para guardar las pulsaciones de teclas.

Editar:

Si desea directorios primero, y luego todo lo que no es un directorio segundo, use esto:

ls -la | grep "^d" && ls -la | grep -v "^d"

once81
fuente
1
Este comando no enumera todo si hay, por ejemplo, sockets o FIFO en la carpeta
Studer
1
Esa versión editada aún debería funcionar con otros tipos. El primer grep dice todo lo que comienza con una 'd', y el segundo dice todo lo que no comienza con una 'd'. Seguramente todo comienza con un anuncio o no, ¿verdad?
Ry4an Brase
1
@ Mark - ¿Por qué no simplemente hacer ls -la | grep "^d" && ls -la | grep "^-" && ls -la | grep -v -E "^d|^-|^total":?
FCTW
1
Para hacer que el comando @ FCTW sea un alias OSX, agregue esto a su ~ / .profile:alias la="ls -la | grep \"^d\" && ls -la | grep \"^-\" && ls -la | grep -E \"^d|^-\" -v | grep -v \"^total\""
aliteralmind
2
He encontrado una notación más corta que funciona: ls -la|grep ^d;ls -la|grep -v ^d(no se requieren comillas y se reemplazan &&por ;). Otra opción es introducir una variable y luego evaluarla: a="ls -la|grep ^d";eval $a;eval $a -v. Podría ser útil para evitar repeticiones cuando se especifican muchas más opciones para ls/ grep. También existe esa ls -la --group-directories-firstopción, sin embargo, la imo más corta esls -la|sort
Steven Pribilinskiy
205

Me encanta * nix y me encanta ver la inventiva que entra en algunas de estas respuestas ...

El mío no es tan elegante en GNU Linux:

alias ls='ls --color -h --group-directories-first'

Dado que me siento más cómodo con mis aplicaciones Linux CLI, también tiendo a actualizar coreutils en OSX:

brew install coreutils
alias ls='/usr/local/bin/gls --color -h --group-directories-first'
jonathanserafini
fuente
66
desafortunadamente, esto no funciona en el terminal osx, ya que la opción no está disponible.
MEM
77
re love: ¿Eso es sarcasmo? Si es así, estaría de acuerdo.
allyourcode
44
El propósito de alias ls es definir los elementos de configuración que quiero usar el 90% del tiempo. Menos pulsaciones de teclas para lograr la salida deseada. Si alguna vez desea tener una salida ls nativa, siempre puede / bin / ls.
jonathanserafini
44
@MEM Si está utilizando OS X y le gusta usar Terminal, brew install bash entonces debería , ¡esto funcionará! :)
Andrew Ashbacher
55
Mi opinión: esto debería haber sido la respuesta aceptada, ya que enumera una opción de línea de comandos para llevar a cabo exactamente el objetivo, en lugar de un conjunto complicado de etc de grep
Ryan Griggs
17

Para usuarios de Mac coreutils :

brew install coreutils

alias ls='ls --color -h --group-directories-first'

Asumiendo que su sistema está listo para homebrew :

Vadym Tyemirov
fuente
77
glsmás bien. ¿Derecho?
Paul Irish
1
Si, por defecto. También puede usar coreutils de forma predeterminada con PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH".
benesch
7

Hay ciertas cosas que quiero ver en una lista de directorios, y hasta ahora ninguna de las respuestas aquí cumple con todos los requisitos a continuación. Mis requisitos para una lista de directorio:

  1. Los directorios y los archivos están ordenados alfabéticamente.
  2. Los directorios se enumeran primero
  3. Los enlaces simbólicos (enlaces simbólicos) se ordenan como archivos
  4. La clasificación no distingue entre mayúsculas y minúsculas
  5. La ordenación ignora todos los caracteres no alfa principales en un nombre de archivo
  6. El listado incluye el recuento total de directorios (excluidos ./y ../), archivos y enlaces
  7. El listado incluye el tamaño total (uso del disco) de directorios y archivos
  8. La lista tiene que tener el mismo aspecto en Linux y Windows (shell Git Bash): esta fue la más difícil de corregir, ya que opciones convenientes como --group-directories-firstno funcionan en Git Bash para Windows

Después de mucho hackear, finalmente se me ocurrió una frase (aunque una línea muy larga ;-)) con la que estoy satisfecho. He asignado esto a un alias llamado 'dir':

ls -dlF --color * .* | head -n2 && ls -AlF | LC_ALL=C grep "^d" | 
LC_ALL=C sort -k 9df && ls -AlF | LC_ALL=C grep "^[l-]" | 
LC_ALL=C sort -k 9df && echo -e `find -maxdepth 1 -type d ! -name . | 
wc -l` Dir\(s\) `du -hs | cut -f 1`\\t\\t`find -maxdepth 1 -type f | 
wc -l` File\(s\) `find -maxdepth 1 -type f -print0 | du -ch --files0-from=- | 
tail -n 1 | cut -f 1`\\t\\t`find -maxdepth 1 -type l | wc -l` Link\(s\)

Para hacer las cosas más fáciles de administrar, se me ocurrieron comandos separados para generar cada segmento de la lista de directorios a mi gusto, luego los ensamblé juntos usando el &&operador.

  • ls -dlF --color * .* | head -n2- Extracto ./y ../. No queremos pasarlos sortporque ya están en el orden correcto, y ordenarlos puede hacer que ../se enumeren primero. La -dopción es deshacerse de la línea "total"; Me gusta agregar -Fpara mostrar la barra diagonal final para directorios (también marcará enlaces simbólicos con "@" cuando hagas un plano ls -F).

  • ls -AlF | LC_ALL=C grep "^d" | LC_ALL=C sort -k 9df- Extraiga los directorios y ordénelos por nombre de archivo (novena columna), ignorando los caracteres que no sean alfa / espacio ( dopción) y mayúsculas y minúsculas ( fopción). La ls -Aopción excluye ./y ../de la lista ya que ya los extrajimos en el paso anterior. Tiendo a prefijar todos grepy sortcomandos con el LC_ALL=Crestablecimiento de la configuración regional para que (1) la salida sea coherente en los shells de Unix, y (2) a veces se puede ver un rendimiento más rápido ya que ya no tiene la sobrecarga del pesado carácter UTF-8 establecido en tratar con.

  • ls -AlF | LC_ALL=C grep "^[l-]" | LC_ALL=C sort -k 9df - Esto es similar al paso anterior, pero esta vez estamos ordenando archivos y enlaces simbólicos.

  • find -maxdepth 1 -type d ! -name . | wc -l- Obtener el número de directorios, excluyendo ./y ../.

  • find -maxdepth 1 -type f | wc -l - Obtener el número de archivos.

  • find -maxdepth 1 -type l | wc -l - Obtener el número de enlaces simbólicos.

  • du -hs | cut -f 1 - Extraiga el tamaño total de todos los subdirectorios en formato legible para humanos.

  • find -maxdepth 1 -type f -print0 | du -ch --files0-from=- | tail -n 1 | cut -f 1 - Extraiga el tamaño total de todos los archivos en formato legible para humanos.

¡Veamos nuestro nuevo diralias en acción!

ANTES DE:

$ ls -alF
total 22
drwxr-xr-x   13 Tom      Administ     4096 Oct 25 02:38 ./
drwxr-xr-x    3 Tom      Administ        0 Dec 24  2014 ../
drwxr-xr-x   15 Tom      Administ     4096 Sep 17 01:23 .VirtualBox/
-rw-r--r--    1 Tom      Administ      615 Oct 25 02:38 .aliases
-rw-r--r--    1 Tom      Administ    12742 Oct 24 11:47 .bash_history
-rw-r--r--    1 Tom      Administ     3234 Oct 24 15:06 .bash_profile
drwxr-xr-x    1 Tom      Administ        0 Jan 24  2015 .gem/
-rw-r--r--    1 Tom      Administ      586 Oct 24 03:53 .gitconfig
drwxr-xr-x    1 Tom      Administ     4096 Dec 28  2014 .ssh/
drwxr-xr-x    4 Tom      Administ        0 Jan 24  2015 .travis/
-rw-r--r--    1 Tom      Administ     6645 Oct 25 02:38 _viminfo
-rw-r--r--    1 Tom      Administ     4907 Oct 24 15:16 profile
drwxr-xr-x    1 Tom      Administ        0 Oct 24 22:20 tmp/

DESPUÉS:

$ dir
drwxr-xr-x   13 Tom      Administ     4096 Oct 25 02:38 ./
drwxr-xr-x    3 Tom      Administ        0 Dec 24  2014 ../
drwxr-xr-x    1 Tom      Administ        0 Jan 24  2015 .gem/
drwxr-xr-x    1 Tom      Administ     4096 Dec 28  2014 .ssh/
drwxr-xr-x    1 Tom      Administ        0 Oct 24 22:20 tmp/
drwxr-xr-x    4 Tom      Administ        0 Jan 24  2015 .travis/
drwxr-xr-x   15 Tom      Administ     4096 Sep 17 01:23 .VirtualBox/
-rw-r--r--    1 Tom      Administ      615 Oct 25 02:38 .aliases
-rw-r--r--    1 Tom      Administ    12742 Oct 24 11:47 .bash_history
-rw-r--r--    1 Tom      Administ     3234 Oct 24 15:06 .bash_profile
-rw-r--r--    1 Tom      Administ      586 Oct 24 03:53 .gitconfig
-rw-r--r--    1 Tom      Administ     4907 Oct 24 15:16 profile
-rw-r--r--    1 Tom      Administ     6645 Oct 25 02:38 _viminfo
      5 Dir(s) 2.8M           6 File(s) 31K           0 Link(s)

Una desventaja menor es que no puede tener listados de colores, ya que los caracteres de control de color que rodean los nombres de los archivos hacen que la clasificación sea demasiado poco confiable.


ACTUALIZAR

El alias anterior fue dolorosamente lento cuando se ejecutó desde el directorio raíz de un sistema de archivos profundo, por lo que he actualizado a este comando más simple pero mucho más eficaz:

ls -AFoqv --color --group-directories-first | tail -n +2 && find -maxdepth 1 -type f -printf '%s\n' | awk '{total+=$1} END {print total" bytes"}'

Salida de muestra:

$ dir
drwxr-xr-x 1 Tom     0 Mar 29 13:49 .aws/
drwxr-xr-x 1 Tom     0 Mar 29 13:49 .gem/
drwxr-xr-x 1 Tom     0 Mar 29 19:32 .ssh/
drwxr-xr-x 1 Tom     0 Mar 29 13:49 .zbstudio/
drwxr-xr-x 1 Tom     0 Jun 16  2016 temp/
drwxr-xr-x 1 Tom     0 Jul 13  2016 vimfiles/
-rw-r--r-- 2 Tom   365 Mar 30 10:37 .aliases
-rw-r--r-- 1 Tom 16028 Mar 30 12:12 .bash_history
-rw-r--r-- 2 Tom  2807 Mar 30 12:12 .bash_profile
-rw-r--r-- 2 Tom  2177 Mar 29 23:24 .functions
-rw-r--r-- 1 Tom  1091 Mar 30 10:34 .gitconfig
-rw-r--r-- 1 Tom  8907 Mar 29 14:45 _viminfo
-rw-r--r-- 1 Tom  2444 Jul 13  2016 _vimrc
33819 bytes

Dado que la nueva versión de Git Bash para Windows es compatible --group-directories-first, ya no tenemos que recurrir a ella sort. Aunque el nuevo alias no muestra tanta información como el alias anterior, las ganancias de rendimiento valen más que la pena. Como beneficio adicional, ¡también obtienes colores!

Thdoan
fuente
¡Gran respuesta! Pero cuando dices: "Después de mucho hackear, finalmente se me ocurrió una frase ..." Sí, de hecho, eso no es realmente una "frase única" en el sentido clásico. Puede tener sentido tomar esa lógica y convertirla en un script de shell independiente y simplemente ejecutarlo o llamarlo como un alias.
JakeGould
@JakeGould ¡Eres rápido! Aún no he terminado de leer mi respuesta y ya terminaste de leerla y dejaste un comentario :). Sí, es un candidato principal para una función, pero era demasiado vago en ese momento, así que lo tiré a mi archivo .bash_aliases. Por otro lado, generalmente solo escribo una función cuando no puedo hacer algo sin pasar parámetros.
Thdoan
@ 10basetom: Pregunta rápida: ¿Cómo se obtienen los diferentes colores para las columnas en ls? Puedo colorear los nombres de archivo por tipo de archivo usando ls --color, pero no veo una manera de obtener esos colores útiles para las columnas. Cual es el secreto
Pirx
@Pirx Creo que las columnas están coloreadas por el resaltado de sintaxis predeterminado de Stack Exchange :-).
Thdoan
Sí, ese parece ser el caso, pero es una gran idea, y las soluciones están en ;-)
Pirx
6

Tiene varias opciones, dependiendo de si desea mantener el orden alfabético.

Simplemente podrías probar:

ls -al | ordenar -k1 -r

o esto, para mantener el orden alfabético de los archivos con los mismos permisos:

ls -al | ordenar -k1,1 -k9,9 -r

o, como dijo once81 (pero esta versión enumera todo):

ls -la | grep "^ d" && ls -la | grep "^ -" && ls -al | grep -v "^ [d | -]"

Studer
fuente
1
Esta es una mejor solución de la OMI. Usar varios procesos y tuberías para ordenar en lugar de tuberías para ordenar parece un poco al revés. Especialmente desde ls- al|sort -k1 -rtrabajos. Lo que faltaba es solo la -rbandera.
brice
@brice Lo que me molesta sobre 'sort' es eso ./y ../no serán las dos primeras líneas, en ese orden. Aparte de eso, estoy de acuerdo en que es la solución más eficiente.
Thdoan
¿Cómo colorear la salida?
Danijel
5

A la respuesta de delerious010 , agregaría que si desea un pedido antiguo:

LANG=C ls -la --group-directories-first

(o use LC_ALL o LANGUAGE o LC_COLLATE establecido en "C").

Esto dará algo similar a:

.
..
DIR
Dir
dir
.hidden
123
UC_FILE
Uc_file
lc_file

Aunque, si recuerdo correctamente, los archivos de puntos ocultos aparecieron originalmente antes que los directorios.

Dennis Williamson
fuente
2

Aquí hay una función para hacer esto (bash o zsh): y ... no estoy sugiriendo que esta sea la mejor manera, pero es la que se me ocurrió y estoy usando en este momento:

función lss
{
    # Muestra la lista de directorios con directorios en la parte superior.

    comando ls --color = siempre $ @ | egrep '^ d | total'
    comando ls --color = siempre $ @ | egrep -v '^ d | total';
}
Súper mágico
fuente
Solo para tu información, esto no parece funcionar. Debe usar el formato de listado largo ( ls -l) para filtrar por tipo de archivo como ese. Además, este comando se romperá en espacios (en bash). Debe citar así: "$@"si desea utilizar este enfoque, puede hacer algo así:function lss {local temp="$(command ls -l --color=always "$@")"; egrep --color=never '^d|total' <<<"$temp"; egrep --color=never -v '^d|total' <<<"$temp"}
Seis
2

ls -laX le mostrará los directorios primero en orden alfabético, pero atornillará la lista de archivos.

Opciones largas:

ls
    -l    # List
    --all
    -X    # Sort alphabetically by entry extension
Poli
fuente
Esto solo funcionaría si pudiera estar absolutamente seguro de que cada directorio no tenía puntos en su nombre.
once81
1

De otra manera ...

find . -d 1 -type d | ls -la | sort -r 

O

ls -la | sort -r

O

d=`find . -type d -d 1`;f=`find . -type f -d 1`; echo -e -DIRS- "\n$d\n" -FILES- "\n$f"
Eddie B
fuente
¿Qué hacen estos? ¿Dónde aprendiste a escribirlos?
Tamara Wijsman
Bueno, mi sistema operativo preferido es Debian Linux. La versión del paquete gnu core utils de Debian de ls admite la opción --show-directorios-first ... cuando comencé a usar OSX, simplemente tomé todos mis archivos bash dot de mi caja Debian y los dejé en mi directorio de inicio ... tuve un montón de bash_aliases que se rompieron, así que ... Fue entonces cuando tuve que encontrar algunas soluciones para mis alias ...
Eddie B
El primero es un poco redundante ... Realmente no hay razón para ordenar los directorios, ya que es el orden que necesitamos modificar, no los directorios ... 'ls -la | sort -r 'es lo que realmente funciona. Básicamente está diciendo ... 1) A) Buscar. -d 1 -tipo d (Comience desde este directorio, busque la profundidad de un directorio y busque solo directorios) B) ls -la (enumere todos los atributos de los archivos) C) Ordénelos en reversa 2) Haga como 1) simplemente suelte el hallazgo. .. no es necesario ... en realidad me gusta más la solución de Studers ... :-)
Eddie B
1

TL; DR

alias ls='ls -lhF --color'

list_sorted() {
    ls $* | grep "^d";
    ls $* | grep "^-";
    ls $* | grep -v -E "^d|^-|^total"
}

alias ll=list_sorted

Explicación

Utilizo una combinación de las soluciones proporcionadas en las respuestas y comentarios aquí.

Defecto ls

En primer lugar, sobrescribo el comportamiento predeterminado para ls:

  • -l: Mostrar siempre la lista como una lista vertical unidimensional
  • -h: Muestra los tamaños de los archivos de forma legible para los humanos (por ejemplo, 4.0K en lugar de 4096)
  • -F: Mostrar indicadores como una barra inclinada final para directorios
alias ls='ls -lhF --color'

Extendido ll

A continuación, escribo una función que contiene la lógica de clasificación. Por cada uno lsle paso los argumentos pasados ​​originalmente. Eso me permite usar el alias de un directorio de trabajo diferente al que quiero enumerar (es decir ls -a ~).

Además, cada llamada a lsse canaliza a un grepcomando. Aquí, ocurre la clasificación. ls -l | grep "^d"por ejemplo solo enumera directorios. Si los directorios se deben enumerar primero, esto también debe ser lo primero en la función. Lo siguiente son los archivos.

Por último, muestro todo lo que no es ni un directorio ni un archivo (ni la línea que muestra el tamaño total del contenido del directorio). Esto se realiza mediante grepping directoy, entradas de archivo regulares y la entrada total y luego invirtiendo el resultado a través del -vargumento.

list_sorted() {
    # List directories
    ls $* | grep "^d";
    # List regular files
    ls $* | grep "^-";
    # List everything else (e.g. symbolic links)
    ls $* | grep -v -E "^d|^-|^total"
}

Finalmente, alias la función a un nuevo comando. En particular, no quiero sobrescribir lsen caso de que mi función se rompa en algunos escenarios. Entonces quiero poder usar ls. Alternativamente, siempre puede invocar el lscomando sin alias invocando \ls.

alias ll=list_sorted

Notas

  • Lo uso en ;lugar de &&como delimitador para los comandos. De lo contrario, uno no puede enumerar el contenido de los directorios que no contienen directorios (el primer comando ls se evalúa como falso, por lo que no permite la ejecución del siguiente comando ya que está acoplado con &&. ;Evita eso).
Kleinfreund
fuente
0

Esta es una solución de script. Enumera solo los nombres, sin datos de inodo, alfabéticos, sin distinción entre mayúsculas y minúsculas, formateados en columnas. Aunque es mayor de fila en lugar de columna mayor, como la salida predeterminada de ls. Las columnas se vuelven un poco desordenadas si hay un nombre de archivo con> 26 caracteres.

rm -f /tmp/lsout
ls -1p | grep / | sort -f >> /tmp/lsout
ls -1p | grep -v / | sort -f >> /tmp/lsout

IFS=$'\n' read -d '' -r -a lines < /tmp/lsout

printf "%-24s  %-24s  %-24s\n" "${lines[@]}"

Y otro, con algo de formato extra.

rm -f /tmp/lsout
echo "  ---- Directories ---- " >> /tmp/lsout
ls -1p | grep / | sort -f >> /tmp/lsout
IFS=$'\n' read -d '' -r -a lines < /tmp/lsout
printf "%-24s  %-24s  %-24s\n" "${lines[@]}"

rm -f /tmp/lsout
echo "  ------- Files ------- " >> /tmp/lsout
ls -1p | grep -v / | sort -f >> /tmp/lsout
IFS=$'\n' read -d '' -r -a lines < /tmp/lsout
printf "%-24s  %-24s  %-24s\n" "${lines[@]}"

La salida para el último tiene el siguiente aspecto, menos los colores:

  ---- Directories ----   archive/                  bookmarks/              
Desktop/                  Documents/                Downloads/              
fff/                      health/                   Library/                
Movies/                   Music/                    Pictures/               
Public/                   rrf/                      scifi/            
testdir/                  testdir2/                                         
  ------- Files -------   @todo                     comedy            
delme                     lll                       maxims                  
schedule                  vtokens style

Solo recuerde no alias o cambiar el comportamiento predeterminado de ls ya que este script lo llama.

Igorio
fuente