15 votos

¿Por qué `echo -n` no funciona en este script en la terminal de Mac?

Estoy aprendiendo shell desde tutorialspoint hoy:http://www.tutorialspoint.com/unix/unix-shell-loops.htm

Y copié este bloque de código a un archivo loop.sh:

#!/bin/sh

a=0
while [ "$a" -lt 10 ]    # este es loop1
do
   b="$a"
   while [ "$b" -ge 0 ]  # este es loop2
   do
      echo -n "$b "
      b=`expr $b - 1`
   done
   echo
   a=`expr $a + 1`
done

Pero al ejecutarlo, obtengo cosas como:

...
-n 4
-n 3
-n 2
-n 1
-n 0
...

Aparentemente, la bandera -n no funciona en echo -n "$b ".

Luego moví el mismo archivo a mi sistema virtual Ubuntu. Lo ejecuté.

Obtuve

0
1 0
2 1 0
3 2 1 0
4 3 2 1 0
5 4 3 2 1 0
6 5 4 3 2 1 0
7 6 5 4 3 2 1 0
8 7 6 5 4 3 2 1 0
9 8 7 6 5 4 3 2 1 0

Estoy confundido, aunque Ubuntu utiliza dash como su sh predeterminado, pero OSX utiliza el bourne shell oficial como su sh, ¿por qué falla el script aquí? ¿Cómo puedo arreglarlo?

25voto

Ido Schacham Puntos 1373

Echo es tanto un programa binario (/bin/echo) como un comando interno en algunas cáscaras como bash y sh. Como dice man echo,

 Algunas cáscaras pueden proporcionar un comando echo interno que es similar o idéntico a esta utilidad. Especialmente, el echo interno en sh (1) no acepta la opción -n. Consulte la página manual de builtin(1).

Para arreglar esto, puede cambiar su script para usar bash configurando la primera línea a

#!/bin/bash

O cambiar su llamada a echo a

/bin/echo -n "$b "

0 votos

Entonces, ¿tutorialspoint cometió un error?

1 votos

Posiblemente, pero sh no es igual en todas partes, por ejemplo, en OS X es un enlace a bash, en otros sistemas Unix puede ser ash, etc. (incluso sh) y la definición de echo en POSIX dice que -n no es portable.

1 votos

@Zen, Tutorials.com probablemente asumió Linux. Mark, tienes toda la razón. Dado que esto está en Ask Different, respondí para OS X.

16voto

jlliagre Puntos 196

echo no es portable como has experimentado. Te sugeriría usar la alternativa POSIX printf:

printf "$b "

Ten en cuenta que en el caso general, si no sabes de antemano lo que contiene $b, deberías usar en su lugar:

printf "%s " "$b"

0 votos

Solo una nota rápida de que si algo en $b empieza con un guión, debes hacer printf -- "$b " de lo contrario arrojará un error.

0 votos

@Ulukai Eso es correcto pero no es lo suficientemente robusto, ya que aun así fallaría si $b contiene %. Mi sugerencia se limitaba al caso del OP.

2voto

user348173 Puntos 1013

Agregar '\c' según la documentación de "man echo" parecería hacer esto por mí. Así que ... en la línea 9 el cambio sería como se muestra a continuación

#!/bin/sh

a=0
while [ "$a" -lt 10 ]    # this is loop1
do
   b="$a"
   while [ "$b" -ge 0 ]  # this is loop2
   do
      echo "$b \c"
      b=`expr $b - 1`
   done
   echo
   a=`expr $a + 1`
done

0 votos

Esto funcionará para algunas versiones de echo (bajo algunas condiciones), pero en otros casos podría imprimir "\c" como parte de la salida (a menos que también suministres la opción -e, pero entonces algunas versiones imprimirán eso...). En general, si valoras tu cordura, utiliza printf en lugar de echo para cualquier situación donde necesites omitir la nueva línea y/o procesar secuencias de escape.

2voto

Ron Puntos 34

El eco incorporado para /bin/sh en macOS no admite la opción -n. Puedes usar las siguientes alternativas:

bash

Usar /bin/bash funciona. Pero no me gusta usarlo para scripts porque no está disponible por defecto, por ejemplo, en FreeBSD. En Linux sí está disponible.

eco incorporado y tr

Si quieres usar el echo incorporado (por ejemplo, al mostrar una contraseña y no quieres que aparezca en ps) y quieres que sea más portable, puedes usar:

echo hello | tr -d '\n'

printf o /bin/echo

De otra manera, printf o /bin/echo -n también son buenas opciones.

Solo ten en cuenta que printf toma una cadena formateada, por lo que si incluyes una variable en la cadena que puede incluir un carácter % o \, puede causar problemas. Por ejemplo:

$ w=%world ; printf "hello $w"
printf: %w: invalid directive
hello %

En ese caso puedes usar %s como cadena de formato.

$ w=%world ; printf %s "hello $w"
hello %world

sufijo \c

Otra opción es agregar \c al final de la cadena al usar echo (consultar man echo en macOS). Funciona bien en macOS pero no es muy portable.

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X