El resultado de ls *, ls ** y ls ***

86

Sé que usar el comando lsenumerará todos los directorios. Pero, ¿qué hace el ls *comando? Lo usé y solo enumera los directorios. ¿La estrella en frente de lssignifica qué tan profundo puede enumerar los directorios?

Andy M
fuente

Respuestas:

155

lsenumera los archivos y el contenido de los directorios que se pasan como argumentos, y si no se proporciona ningún argumento, enumera el directorio actual. También se le puede pasar una serie de opciones que afectan su comportamiento (ver man lspara más detalles).

Si lsse le pasa un argumento llamado *, buscará un archivo o directorio llamado *en el directorio actual y lo enumerará como cualquier otro. lsno trata al *personaje de ninguna otra forma que no sea otra.

Sin embargo, si se ls *trata de una línea de comando de shell , el shell lo expandirá de *acuerdo con las reglas de globbing del shell correspondiente (también denominado Generación de nombre de archivo o Expansión de nombre de archivo ).

Si bien diferentes shells admiten diferentes operadores de globbing, la mayoría de ellos están de acuerdo con el más simple *. *como patrón significa cualquier número de caracteres, por lo *que globse expandirá a la lista de archivos en los directorios actuales que coinciden con ese patrón. Sin embargo, existe la excepción de que un carácter de punto ( .) en un nombre de archivo debe coincidir explícitamente, por lo que en *realidad se expande a la lista de archivos y directorios que no comienzan con .(en orden lexicográfico).

Por ejemplo, si el directorio actual contiene los archivos llamados ., .., .foo, -ly foo bar, *se ampliará por la cáscara de dos argumentos para transmitir a ls: -ly foo bar, por lo que será como si lo hubiera escrito:

ls -l "foo bar"

o

'ls' "-l" foo\ bar

Cuáles son tres formas de ejecutar exactamente el mismo comando. En los 3 casos, el lscomando (que probablemente se ejecutará desde /bin/lsuna búsqueda de directorios mencionada en $PATH) se pasará por esos 3 argumentos: "ls", "-l" y "foo bar".

Por cierto, en este caso, lstratará el primero (estrictamente hablando segundo ) como una opción.

Ahora, como dije, diferentes proyectiles tienen diferentes operadores de globos. Hace unas décadas, zshintroduje el **/operador¹, que significa hacer coincidir cualquier nivel de subdirectorios, abreviatura (*/)#y ***/que es lo mismo, excepto que sigue enlaces simbólicos mientras desciende los directorios.

Hace unos años (julio de 2003 ksh93o+), ksh93decidió copiar ese comportamiento, pero decidió hacerlo opcional y solo cubrió el **caso (no ***). Además, si bien **solo no era especial en zsh(solo significaba lo mismo que *en otros shells tradicionales, ya que **significa cualquier número de caracteres seguido de cualquier número de caracteres), en ksh93, **significaba lo mismo que **/*(por lo que cualquier archivo o directorio debajo del actual (excluyendo archivos ocultos).

bashcopiado ksh93unos años más tarde (febrero de 2009, bash 4.0), con la misma sintaxis pero con una desafortunada diferencia: bash **era como zsh's ***, es decir, seguía enlaces simbólicos cuando recurría a subdirectorios que generalmente no es lo que quieres que haga y puede tener efectos secundarios desagradables. Se corrigió parcialmente en bash-4.3 en que los enlaces simbólicos todavía se seguían, pero la recursión se detuvo allí. Fue completamente reparado en 5.0.

yashagregado **en la versión 2.0 en 2008, habilitado con la extended-globopción. Su implementación es más cercana a zshla de que **solo no es especial. En la versión 2.15 (2009), agregó ***like en zshy dos de sus propias extensiones: .**e .***incluir directorios ocultos al recurrir (en zsh, el D calificador glob (como en **/*(D)) considerará archivos y directorios ocultos, pero si solo desea atravesar ocultos dirs pero no expandir archivos ocultos, necesita ((*|.*)/)#*o **/[^.]*(D)).

La concha de pescado también es compatible **. Al igual que la versión anterior de bash, sigue enlaces simbólicos al descender el árbol de directorios. En ese shell, sin embargo, **/*no es lo mismo que **. **es más una extensión de *que puede abarcar varios directorios. En fish, **/*.ccoincidirá a/b/c.cpero no a.c, mientras que a**.ccoincidirá a.ce ab/c/d.cy zsh's **/.*, por ejemplo, tiene que ser por escrito .* **/.*. Allí, ***se entiende como **seguido por *lo mismo que **.

tcshTambién agregó una globstaropción en V6.17.01 (mayo de 2010) y admite ambos **y ***à la zsh.

Así pues, en tcsh, bashy ksh93, (cuando la opción correspondiente está activada ( globstar)) o fish, **expande todos los archivos y directorios por debajo de la actual, y ***es la misma que **para fishun enlace simbólico atravesar **para tcshcon globstar, y al igual que *en bashy ksh93(aunque es no es imposible que las futuras versiones de esos shells también atraviesen enlaces simbólicos).

Arriba, habrá notado la necesidad de asegurarse de que ninguna de las expansiones se interprete como una opción. Para eso, harías:

ls -- *

O:

ls ./*

Hay algunos comandos (no importa ls) donde el segundo es preferible ya que incluso con --algunos nombres de archivo pueden tratarse especialmente. Es el caso de -la mayoría de utilidades de texto, cdy pushdy nombres de archivo que contienen el =carácter de awkpor ejemplo. Preceder ./a todos los argumentos elimina su significado especial (al menos para los casos mencionados anteriormente).

También debe tenerse en cuenta que la mayoría de los shells tienen una serie de opciones que afectan el comportamiento global (como si los archivos de puntos se ignoran o no, el orden de clasificación, qué hacer si no hay coincidencia ...), vea también el $FIGNOREparámetro enksh

Además, en todos los depósitos, pero csh, tcsh, fishy zsh, si el patrón de comodines no coincide con ningún archivo, el patrón se pasa como argumento sin expandir lo que provoca confusión y posiblemente insectos. Por ejemplo, si no hay un archivo no oculto en el directorio actual

ls *

Realmente llamará lscon los dos argumentos lsy *. Y como no hay ningún archivo, por lo que *tampoco se llama ninguno, verá un mensaje de error de ls (no el shell) como:, ls: cannot access *: No such file or directoryque se sabe que hace que la gente piense que fue lseso lo que realmente estaba expandiendo los globos.

El problema es aún peor en casos como:

rm -- *.[ab]

Si no hay *.ani *.barchivo en el directorio actual, entonces es posible llegar a borrar un archivo llamado *.[ab]por error ( csh, tcshy zshreportaría un ningún partido de error y no llamarían rm(y fishno soporta los [...]comodines)).

Si desea pasar un literal *a ls, debe citar ese *carácter de alguna manera como en ls \*o ls '*'o ls "*". En shells similares a POSIX, el globbing se puede desactivar por completo usando set -o noglobo set -f(este último no funciona a zshmenos que en sh/ kshemulación).


¹ Si bien (*/)#siempre fue compatible, primero fue breve como ..../en zsh-2.0 (y posiblemente antes), luego ****/en 2.1 antes de obtener su forma definitiva **/en 2.2 (principios de 1992)

Stéphane Chazelas
fuente
22
Muy buena respuesta!
Andrea Corbellini
77
Otro buen ejemplo es find -name *. Especialmente con patrones más complejos, si hay exactamente una coincidencia en el directorio actual, las personas a menudo no se darán cuenta de que no están pasando el asterisco find.
njsg
Sigo dando +1, ¡estoy muy feliz de ver a Stephane Chazelas activo aquí en unix.stackexchange.com ! ¡Grandes contribuciones, Stephane, como siempre!
Dimitre Radoulov
1
En peces, *.[ab]intentaría eliminar todo lo que termina en .[ab]. [No es especial en pescado.
Konrad Borowski
35

El comando lspredeterminado es ls .: Listar todas las entradas en el directorio actual .

El comando ls *significa 'ejecutar ls en la expansión del *patrón de shell'

El *shell procesa el patrón y se expande a todas las entradas en el directorio actual, excepto aquellas que comienzan con a .. Irá un nivel más profundo.

La interpretación de *patrones dobles o triples depende del caparazón real utilizado.

*es un comodín que coincide con 0 o más caracteres. Algunos proyectiles modernos se repetirán en subdirectorios al ver el **patrón.

Dennis Kaarsemaker
fuente
17
Excepto ese extra * hacen añadir algo, ver la otra respuesta que explica la Globstar. También debe quedar claro que ls no tiene nada que ver con los asteriscos, nunca ha pasado ninguno de estos asteriscos. Corre echo ls *para ver qué se ejecutará cuando escribas ls *.
njsg
12

Puede desmitificar todo el proceso escribiendo en echolugar de lsprimero, para ver a qué se expande el comando:

$ echo *
Applications Downloads Documents tmp.html

Entonces, en este caso, se ls *expande als Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

Entonces no hay cambio. Esto supone que lo está utilizando bashcomo caparazón: la mayoría de las personas lo son y las diferentes capas tienen un comportamiento diferente. Si usa ashor csho kshor zsh, puede esperar que las cosas funcionen de manera diferente. Ese es el punto de tener diferentes conchas.

Entonces, intentemos algo diferente (todavía con bash) para tener una idea de lo que el *operador globbing ( ) puede hacer por nosotros. Por ejemplo, podemos filtrar por parte del nombre:

$ echo D*
Downloads Documents

Y curiosamente, una barra diagonal final es una parte implícita de cualquier nombre de directorio. Por */lo tanto , solo generará los directorios (y enlaces simbólicos a los directorios):

$ echo */
Applications/ Downloads/ Documents/

Y podemos hacer algunos filtros en múltiples niveles colocando barras en el medio:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

Como el Downloadsdirectorio no contiene ningún subdirectorio, no termina en la salida. Esto es muy útil solo para examinar los archivos que desea. Yo uso comandos como este todo el tiempo:

$ ls -l /home/*/public_html/wp-config.php

Esto enumera, si hay alguno, todos los wp-config.phparchivos que existen en el nivel base del public_htmldirectorio de cualquier usuario . O tal vez para ser más completo:

$ find /home/*/public_html/ -name wp-config.php

Esto encontrará cualquier wp-config.phparchivo en los public_htmldirectorios de cualquier usuario o en cualquiera de sus subdirectorios, pero funcionará de manera más eficiente que solo find /home/ -name wp-config.phpporque no examinará nada más que los public_htmldirectorios para cada uno de los usuarios.

tylerl
fuente
1
"Esto supone que está utilizando bashcomo su shell" ← y que el globstar no está habilitado. shopt -s globstare inténtalo de nuevo ...
njsg
Otra forma de desmitificar es la set -xque comenzará a imprimir el comando "real" ejecutado cada vez (desactivar con set +x).
ShreevatsaR
10

En algunos shells, incluido bash 4.x con la globstaropción habilitada, **se realizará un recursivo glob, descendiendo directorios coincidentes. Los asteriscos adicionales no modifican más esta operación.

Ignacio Vazquez-Abrams
fuente
1
Sin embargo, como dije en mi respuesta, tenga en cuenta que, al contrario ksh93y zsh, bashatraviesa los enlaces simbólicos en la recursión, que generalmente no es deseada.
Stéphane Chazelas
Eso ahora se ha solucionado en bash 4.3
Stéphane Chazelas
1

Si desea "sumergirse profundamente", use la opción ls -R (recursiva), o use find, así:

find . -ls

"find" se sumergirá en la parte inferior del árbol de directorios (al igual que 'ls -R'), y tiene muchas más opciones, como enumerar directorios (-type d), solo archivos (-typef) o mostrar archivos que tienen otros características (ningún usuario en / etc / passwd, permisos específicos y mucho más). "find" también es algo más seguro en las secuencias de comandos (debido a reglas de bloqueo inconsistentes entre shells, así como escapes especiales para archivos con guiones, etc.).

el uso de comodines de shell no funcionará solo con un asterisco '*' en los archivos de puntos. Para enumerar solo los archivos de puntos, use:

ls .??*

Razzlephrazz
fuente
-1

Extra * no agrega nivel de profundidad. Pero si lo intentas

 ls */*/*

- obtendrá una lista de subcarpetas de subcarpetas en carpetas en la carpeta actual ...

VB9-UANIC
fuente
Incorrecto. Dependiendo del caparazón, *s adicionales agregarán nivel de profundidad.
njsg
Entonces, ¿qué capa agregará nivel de profundidad en las estrellas adicionales?
VB9-UANIC
Varios. Incluyendo GNU bashcon la opción globstar, el shell korn y zsh. Y posiblemente otros, supongo. unix.stackexchange.com/a/62665/14831
njsg
-1

Mi agarre principal es ese echo ** / *. Ext generalmente ...

Mayo o mayo no: enumere un archivo .ext en el directorio actual

Mayo o mayo no: incluye archivos. *. Ext

En general, preferiría que la expresión global sea '** /' y que pueda dar como resultado una cadena nula (sin subdirectorio). Así es como convierto expresiones globales en la entrada del programa. Por supuesto, me aseguro de que haya comentarios que expliquen esto en ejemplos de uso.

Antonio
fuente