¿Por qué echo "bar" -n es diferente de echo -n "bar"?

10

Comparar

echo -n "bar"

con

echo "bar" -n

El primero hace lo que creo que se supone que debe hacer (imprime "barra" sin una nueva línea), mientras que el segundo no. ¿Es esto un error o por diseño? ¿Por qué es diferente de muchos programas cli en que no puedes mover las opciones? Por ejemplo, tail -f /var/log/messageses exactamente lo mismo que tail /var/log/messages -f. A veces hago esto último cuando olvido que quería el primero, porque internamente las opciones y argumentos se reorganizan, generalmente por getopt .

Actualización: sí, originalmente nerf-ed mi pregunta. Eliminé el nerf, tendrás que ver el historial para que algunas de las respuestas tengan sentido.

xenoterracida
fuente
3
Por lo que veo, la diferencia es inmediatamente obvia. echo -n "bar"da "bar", mientras echo "bar" -nda "bar -n"
phunehehe

Respuestas:

18

Como la mayoría de los demás han observado, "-n" se interpreta literalmente si se coloca en cualquier lugar pero inmediatamente después del echocomando.

Históricamente, las utilidades de UNIX eran así: buscaban opciones solo inmediatamente después del nombre del comando. Probablemente, BSD o GNU fueron los pioneros del estilo más flexible (aunque podría estar equivocado), ya que incluso ahora POSIX especifica la forma antigua como correcta (consulte la Directriz 9, y también man 3 getopten un sistema Linux). De todos modos, a pesar de que la mayoría de las utilidades de Linux en estos días usan el nuevo estilo, hay algunas reservas como echo.

Echoes un desastre, en cuanto a estándares, en el sentido de que había al menos dos versiones fundamentalmente conflictivas en juego cuando POSIX surgió. Por un lado, tiene el estilo SYSV, que interpreta los caracteres con barra invertida pero trata sus argumentos literalmente, sin aceptar opciones. Por otro lado, tiene un estilo BSD, que trata una inicial -ncomo un caso especial y genera absolutamente todo lo demás literalmente. Y como echoes tan conveniente, tiene miles de scripts de shell que dependen de un comportamiento u otro:

echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --

Debido a la semántica de "tratar todo literalmente", es imposible incluso agregar una nueva opción echosin romper las cosas. Si GNU usara el esquema de opciones flexibles, el infierno se desataría.

Por cierto, para una mejor compatibilidad entre las implementaciones de shell Bourne, use en printflugar deecho .

ACTUALIZADO para explicar por qué echoen particular no utiliza opciones flexibles.

Jander
fuente
voto positivo ya que eres el único en mencionar que es el comportamiento getopt esperado.
Geoffrey Bachelet
@jander ¿por qué echo es un "holdout"? Creo que es un gnu coreutil?
xenoterracide
@xeno: He actualizado mi respuesta. Básicamente, GNU no quería romper cosas.
Jander
1
La aceptación de opciones después de la primera no opción es específica para las utilidades GNU y el programa que utiliza las instalaciones getopt de GNU libc . El usuario siempre puede obtener un comportamiento compatible con versiones anteriores al configurar la variable de entorno . POSIXLY_CORRECT
Gilles 'SO- deja de ser malvado'
1
Para el caso específico de echo, también hay implementaciones que reconocen -eo -Ecomo opciones. Para la portabilidad, no comience con -ni use algo como printf %s -e.
Gilles 'SO- deja de ser malvado'
9

Las otras respuestas llegan al punto en que puede mirar la página de manual para ver que -n se está convirtiendo en parte de la cadena para hacer eco. Sin embargo, solo quiero señalar que es fácil investigar esto sin el md5sum y hace que lo que está sucediendo sea un poco menos críptico.

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n
Razón
fuente
3
+1 exactamente. Si una tubería no está haciendo lo que espera, pruebe cada parte por separado.
Mikel
6

Wow, las explicaciones de todos son largas.

Es así de simple:

-n es una opción si aparece antes de la cadena, de lo contrario es solo otra cadena que se repetirá.

Elimine el | md5sum y verá que la salida es diferente.

Mikel
fuente
5

Por simple inspección, esto no es un error por diseño ...

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

Prueba este comando por ti mismo:

echo "bar -n" | md5sum

Notarás que el md5 resultante es

a3f8efa5dd10e90aee0963052e3650a1

Acaba de mezclar el uso de -n en eco.

En tu primer código de muestra

echo -n "bar" | md5sum

-n se usa para decir NO poner una nueva línea después de este eco.

Su segunda muestra

echo "bar" -n | md5sum

está tratando -n como un texto literal.

icasimpan
fuente