¿Cuál es la diferencia entre "du -sh *" y "du -sh ./*"?


26

¿Cuál es la diferencia entre du -sh *y du -sh ./*?

Nota: Lo que me interesa son las partes *y ./*.


2
La salida ? uno le mostrará ./ delante del nombre del archivo
Kiwy

Respuestas:


69
$ touch ./-c $ 'a \ n12 \ tb' foo
$ du -hs *
0 a
12 b
0 foo
0 total

Como puede ver, el -carchivo se tomó como una opción duy no se informa (y ve la totallínea debido a du -c). Además, el archivo llamado a\n12\tbnos hace pensar que hay archivos llamados ay b.

$ du -hs -- *
0       a
12      b
0       -c
0       foo

Eso es mejor. Al menos este tiempo -cno se toma como una opción.

$ du -hs ./*
0       ./a
12      b
0       ./-c
0       ./foo

Eso es aun mejor. El ./prefijo evita que -cse tome como una opción y la ausencia de ./antes ben la salida indica que no hay ningún barchivo allí, pero hay un archivo con un carácter de nueva línea (pero vea más abajo 1 para más digresiones sobre eso).

Es una buena práctica usar el ./prefijo cuando sea posible, y si no es así y para datos arbitrarios, siempre debe usar:

cmd -- "$var"

o:

cmd -- $patterns

Si cmdno admite --marcar el final de las opciones, debe informarlo como un error a su autor (excepto cuando sea por elección y documentado como para echo).

Hay casos donde ./*resuelve problemas que --no lo hacen. Por ejemplo:

awk -f file.awk -- *

falla si hay un archivo llamado a=b.txten el directorio actual (establece la variable awk aen b.txtlugar de decirle que procese el archivo).

awk -f file.awk ./*

No tiene el problema porque ./ano es un nombre de variable awk válido, por ./a=b.txtlo que no se toma como una asignación de variable.

cat -- * | wc -l

falla si hay un archivo llamado -en el directorio actual, ya que le dice catque lea desde su stdin ( -es especial para la mayoría de las utilidades de procesamiento de texto y para cd/ pushd).

cat ./* | wc -l

está bien porque ./-no es especial para cat.

Cosas como:

grep -l -- foo *.txt | wc -l

contar el número de archivos que contienen fooson incorrectos porque se supone que los nombres de archivo no contienen caracteres de nueva línea ( wc -lcuenta los caracteres de nueva línea, los que se muestran greppara cada archivo y los que están en los nombres de archivo). Deberías usar en su lugar:

grep -l foo ./*.txt | grep -c /

(contar el número de /caracteres es más confiable ya que solo puede haber uno por nombre de archivo).

Para recursivo grep, el truco equivalente es usar:

grep -rl foo .//. | grep -c //

./* Sin embargo, puede tener algunos efectos secundarios no deseados.

cat ./*

agrega dos caracteres más por archivo, por lo que lo haría alcanzar el límite del tamaño máximo de argumentos + entorno antes. Y a veces no desea que ./se informe en la salida. Me gusta:

grep foo ./*

Daría salida:

./a.txt: foobar

en lugar de:

a.txt: foobar

Otras digresiones

1 . Siento que tengo que ampliar eso aquí, siguiendo la discusión en los comentarios.

$ du -hs ./*
0       ./a
12      b
0       ./-c
0       ./foo

Arriba, ./marcar el comienzo de cada archivo significa que podemos identificar claramente dónde comienza cada nombre de archivo (en ./) y dónde termina (en la nueva línea antes del próximo ./o el final de la salida).

Lo que eso significa es que la salida de du ./*, al contrario de la de du -- *) se puede analizar de manera confiable, aunque no tan fácilmente en un script.

Sin embargo, cuando la salida va a una terminal, hay muchas más formas en que un nombre de archivo puede engañarlo:

  • Los personajes de control, las secuencias de escape pueden afectar la forma en que se muestran las cosas. Por ejemplo, \rmueve el cursor al comienzo de la línea, \bmueve el cursor hacia atrás, \e[Chacia adelante (en la mayoría de las terminales) ...
  • muchos caracteres son invisibles en un terminal que comienza con el más obvio: el carácter de espacio.
  • Hay caracteres Unicode que se parecen a la barra diagonal en la mayoría de las fuentes

    $ printf '\u002f \u2044 \u2215 \u2571 \u29F8\n'
    /    
    

    (vea cómo va en su navegador).

Un ejemplo:

$ touch x 'x ' $'y\bx' $'x\n0\t.\u2215x' $'y\r0\t.\e[Cx'
$ ln x y
$ du -hs ./*
0       ./x
0       ./x
0       ./x
0       .∕x
0       ./x
0       ./x

Muchos xpero yfalta.

Algunas herramientas como GNUls reemplazarían los caracteres no imprimibles con un signo de interrogación (tenga en cuenta que (U + 2215) es imprimible sin embargo) cuando la salida va a un terminal. GNU duno lo hace.

Hay formas de hacer que se revelen:

$ ls
x  x   x?0?.∕x  y  y?0?.?[Cx  y?x
$ LC_ALL=C ls
x  x?0?.???x  x   y  y?x  y?0?.?[Cx

Vea cómo se volvió ???después de que dijimos lsque nuestro conjunto de caracteres era ASCII.

$ du -hs ./* | LC_ALL=C sed -n l
0\t./x$
0\t./x $
0\t./x$
0\t.\342\210\225x$
0\t./y\r0\t.\033[Cx$
0\t./y\bx$

$marca el final de la línea, para que podamos detectar el "x"vs "x ", todos los caracteres no imprimibles y no ASCII están representados por una secuencia de barra invertida (la barra invertida en sí misma se representaría con dos barras invertidas), lo que significa que no es ambigua. Eso era GNU sed, debería ser lo mismo en todas las sedimplementaciones compatibles con POSIX , pero tenga en cuenta que algunas sedimplementaciones antiguas no son tan útiles.

$ du -hs ./* | cat -vte
0^I./x$
0^I./x $
0^I./x$
0^I.M-bM-^HM-^Ux$

(no estándar pero bastante común, también cat -Acon algunas implementaciones). Esa es útil y usa una representación diferente pero es ambigua ( "^I"y <TAB>se muestran de la misma manera, por ejemplo).

$ du -hs ./* | od -vtc
0000000   0  \t   .   /   x  \n   0  \t   .   /   x      \n   0  \t   .
0000020   /   x  \n   0  \t   . 342 210 225   x  \n   0  \t   .   /   y
0000040  \r   0  \t   . 033   [   C   x  \n   0  \t   .   /   y  \b   x
0000060  \n
0000061

Ese es estándar e inequívoco (y consistente de implementación en implementación) pero no tan fácil de leer.

Notarás que ynunca apareció arriba. Ese es un problema completamente no relacionado con du -hs *eso que no tiene nada que ver con los nombres de archivo, pero debe tenerse en cuenta: debido a que duinforma el uso del disco, no informa otros enlaces a un archivo ya listado (no todas las duimplementaciones se comportan así cuando los enlaces duros están listados en la línea de comando).


+1, agradable y completo (por lo que puedo decir ^^). Especialmente me encanta la ventaja "grep -c /". También vale la pena señalar: la ventaja de "./*" sobre "*" aparece en una de las (muchas) buenas respuestas de las Preguntas Frecuentes de Unix (probablemente en faqs.org. Iirc, está en la pregunta acerca de cómo iniciar archivos con una "-").
Olivier Dulac

... y no es una mala práctica tener archivos con nuevas líneas y pestañas en sus nombres? Sé que trato de limitar los nombres a [a-z0-9.+-].
Blacklight Shining

55
@BlacklightShining, es muy malo robar autos, pero es malo dejar tu auto desbloqueado (ignorar las nuevas líneas), especialmente cuando es un auto costoso (script que se ejecuta como un usuario privilegiado, en un servidor con datos confidenciales ...) o cuando estacione en un área áspera ( /tmp) o en un área con muchos automóviles caros ( $HOME) y es aún peor ir a un sitio de preguntas y respuestas y decir que siempre está bien no bloquear su automóvil sin especificar en qué condiciones (en un garaje cerrado, guión escribió solo por usted en una máquina no conectada a ninguna red o almacenamiento extraíble ...)
Stéphane Chazelas

1
@BlacklightShining, las nuevas líneas son inusuales, pero los espacios incrustados son muy comunes hoy en día, particularmente para archivos creados a través de GUI.
alexis

2
@BlacklightShining, sí, aunque ese (como "b "o "a\bb") engañaría a un usuario en un terminal, pero no un script que analiza la salida de du ./*. Probablemente debería agregar una nota al respecto. Lo hare mañana. Tenga en cuenta que antes quise decir privilegiado en el sentido general, no root(aunque se aplica aún más, por rootsupuesto). se permiten nuevas líneas, ignorarlas es un error. los insectos tienen la costumbre de ser explotados. Tienes que medir el riesgo caso por caso. Las buenas prácticas de codificación pueden evitar los problemas en muchos casos. Ciertamente, en SE, debemos crear conciencia.
Stéphane Chazelas

6

No hay diferencia entre una *y ./*en términos de lo que los archivos cualquiera de las listas voluntad. La única diferencia sería con la segunda forma, cada archivo tendría una barra diagonal con un ./prefijo delante de ellos, lo que generalmente significa el directorio actual.

Recuerde que el .directorio es una notación abreviada para el directorio actual.

$ ls -la | head -4
total 28864
drwx------. 104 saml saml    12288 Jan 23 20:04 .
drwxr-xr-x.   4 root root     4096 Jul  8  2013 ..
-rw-rw-r--.   1 saml saml      972 Oct  6 20:26 abcdefg

Puedes convencerte de que estas 2 listas son esencialmente lo mismo si usas echopara ver a qué se expandiría el shell.

$ echo *
$ echo ./*

Estos 2 comandos enumerarán todos los archivos en su directorio actual.

Ejemplos

Podemos hacer algunos datos falsos así:

$ touch file{1..5}
$ ll
total 0
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file1
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file2
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file3
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file4
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file5

Ahora, cuando usamos los echocomandos anteriores , vemos el siguiente resultado:

$ echo *
file1 file2 file3 file4 file5
$ echo ./*
./file1 ./file2 ./file3 ./file4 ./file5

Esta diferencia puede parecer innecesaria, pero hay situaciones en las que desea garantizar a las diversas herramientas de línea de comandos de Unix que les está pasando nombres de archivos a través de la línea de comandos, ¡y nada más!

Entonces, ¿por qué usar ./*?

Como señala la respuesta de @ Stephane , debido a la naturaleza de qué caracteres son legales al nombrar archivos y directorios en Unix, se pueden construir nombres de archivo peligrosos que tienen efectos secundarios inesperados cuando se pasan a varios comandos de Unix en la línea de comando.

Muy a menudo, el uso de ./se utilizará para ayudar a garantizar que los nombres de archivo expandidos se consideren como nombres de archivo cuando se pasan como argumentos a los diversos comandos de Unix.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.