GNU/Linux >> Tutoriales Linux >  >> Linux

¿La diferencia entre "du -sh *" y "du -sh ./*"?

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

Nota:Lo que me interesa es el * y ./* partes.

Respuesta aceptada:

$ touch ./-c $'an12tb' foo
$ du -hs *
0       a
12      b
0       foo
0       total

Como puede ver, el -c El archivo se tomó como una opción para du y no se informa (y se ve el total línea debido a du -c ). Además, el archivo llamado an12tb nos hace pensar que hay archivos llamados a y b .

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

Eso es mejor. Al menos esta vez -c no se toma como una opción.

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

Eso es aún mejor. El ./ prefijo previene -c de ser tomado como una opción y la ausencia de ./ antes de b en la salida indica que no hay b archivo allí, pero hay un archivo con un carácter de nueva línea (pero vea más abajo para más digresiones al respecto).

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

cmd -- "$var"

o:

cmd -- $patterns

Si cmd no es compatible con -- para marcar el final de las opciones, debe informarlo como un error a su autor (excepto cuando es por elección y documentado como para echo ).

Hay casos en los que ./* resuelve problemas que -- no. Por ejemplo:

awk -f file.awk -- *

falla si hay un archivo llamado a=b.txt en el directorio actual (establece la variable awk a a b.txt en lugar de decirle que procese el archivo).

awk -f file.awk ./*

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

cat -- * | wc -l

falla si hay un archivo llamado - en el directorio actual, ya que eso le dice a cat para leer 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

para contar el número de archivos que contienen foo son incorrectos porque asume que los nombres de los archivos no contienen caracteres de nueva línea (wc -l cuenta los caracteres de nueva línea, los generados por grep para cada archivo y los de los propios nombres de archivo). Deberías usar en su lugar:

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

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

Para grep recursivo , el truco equivalente es usar:

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

./* aunque puede tener algunos efectos secundarios no deseados.

cat ./*

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

grep foo ./*

Daría salida:

./a.txt: foobar

en lugar de:

a.txt: foobar

Digresiones adicionales

. 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, ese ./ 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 siguiente ./ o el final de la salida).

Relacionado:¿Cómo agregar el subdirectorio bin del primer directorio en GOPATH a PATH?

Lo que eso significa es que la salida de du ./* , contrario al de du -- * ) se puede analizar de forma fiable, 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 caracteres de control, las secuencias de escape pueden afectar la forma en que se muestran las cosas. Por ejemplo, r mueve el cursor al principio de la línea, b mueve el cursor hacia atrás, e[C adelante (en la mayoría de las terminales)…

  • muchos caracteres son invisibles en una terminal, empezando por el más obvio:el carácter de espacio.

  • Hay caracteres Unicode que tienen el mismo aspecto que la barra oblicua en la mayoría de las fuentes

     $ printf 'u002f u2044 u2215 u2571 u29F8n'
     / ⁄ ∕ ╱ ⧸
    

(ver cómo va en su navegador).

Un ejemplo:

$ touch x 'x ' $'ybx' $'xn0t.u2215x' $'yr0t.e[Cx'
$ ln x y
$ du -hs ./*
0       ./x
0       ./x
0       ./x
0       .∕x
0       ./x
0       ./x

Un montón de x pero y falta.

Algunas herramientas como GNU ls reemplazaría los caracteres no imprimibles con un signo de interrogación (tenga en cuenta que (U+2215) es imprimible) cuando la salida va a un terminal. GNU du no 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

Mira cómo convertido en ??? después de que le dijimos a ls que nuestro conjunto de caracteres era ASCII.

$ du -hs ./* | LC_ALL=C sed -n l0t./x$0t./x $0t./x$0t.342210225x$0t./yr0t.
Linux
  1. ¿La diferencia entre el abastecimiento ('.' o 'fuente') y la ejecución de un archivo en Bash?

  2. ¿La diferencia entre [[ $a ==Z* ]] y [ $a ==Z* ]?

  3. ¿Cuál es la diferencia entre /sbin/nologin y /bin/false?

  4. ¿La diferencia entre enlaces simbólicos y duros?

  5. Diferencia entre /bin y /usr/bin

La diferencia entre más, menos y la mayoría de los comandos

La diferencia entre '$ . Foo' y '$ ./foo'??

¿La diferencia entre Nss y Pam?

¿Cuál es la diferencia entre fsync y syncfs?

Diferencia entre /etc/crontab y crontab -e

¿Cuál es la diferencia entre ls y l?