Usé uno de los siguientes
echo $(stuff)
echo `stuff`
(donde stuff
es, por ejemplo pwd
, o date
o algo más complicado).
Entonces me dijeron que esta sintaxis es incorrecta, una mala práctica, no elegante, excesiva, redundante, demasiado complicada, una programación de culto de carga, novato, ingenuo, etc.
Sin embargo, el comando hace el trabajo, así que ¿qué es exactamente el problema?
shell-script
sh
echo
Kamil Maciorowski
fuente
fuente
echo $(echo $(echo $(echo$(echo $(stuff)))))
también lo hace el trabajo, y aún así es probable que no lo utilizaría, ¿verdad? ;-)stuff
. : DRespuestas:
tl; dr
Una suela
stuff
sería más probable que funcione para usted.Respuesta completa
Lo que pasa
Cuando corres
foo $(stuff)
, esto es lo que sucede:stuff
carreras;$(stuff)
en la invocación defoo
;foo
ejecuta, sus argumentos de línea de comando obviamente dependen de lo questuff
devuelve.Este
$(…)
mecanismo se llama "sustitución de comando". En su caso, el comando principal es elecho
que básicamente imprime sus argumentos de línea de comando en stdout. Entonces, cualquier cosa questuff
intente imprimir en stdout es capturada, pasadaecho
e impresa en stdout porecho
.Si desea que la salida
stuff
se imprima en stdout, simplemente ejecute la suelastuff
.La
`…`
sintaxis tiene el mismo propósito que$(…)
(bajo el mismo nombre: "sustitución de comandos"), aunque existen pocas diferencias, por lo que no puede intercambiarlas a ciegas. Vea estas preguntas frecuentes y esta pregunta .¿Debo evitar
echo $(stuff)
pase lo que pase?Es posible que desee utilizar una razón
echo $(stuff)
si sabe lo que está haciendo. Por la misma razón que debes evitarecho $(stuff)
si realmente no sabes lo que estás haciendo.El punto es
stuff
yecho $(stuff)
no es exactamente equivalente. Esto último significa llamar al operador split + glob en la salida destuff
con el valor predeterminado de$IFS
. Citar dos veces la sustitución del comando evita esto. Citar solo la sustitución de comandos hace que ya no sea una sustitución de comandos.Para observar esto cuando se trata de dividir, ejecute estos comandos:
Y para globbing:
Como puede ver,
echo "$(stuff)"
es equivalente (-ish *) astuff
. Podrías usarlo, pero ¿de qué sirve complicar las cosas de esta manera?Por otro lado, si desea que la salida se
stuff
divida + globbing, entonces puede resultarleecho $(stuff)
útil. Sin embargo, tiene que ser tu decisión consciente.Hay comandos que generan resultados que deben evaluarse (lo que incluye división, globalización y más) y ejecutarse por el shell, por lo que
eval "$(stuff)"
es una posibilidad (vea esta respuesta ). Nunca he visto un comando que necesita su salida para someterse a división adicional + globbing antes de imprimirse . El uso deliberadoecho $(stuff)
parece muy poco común.¿Qué hay de
var=$(stuff); echo "$var"
?Buen punto. Este fragmento:
debe ser equivalente a
echo "$(stuff)"
equivalente (-ish *) astuff
. Si es todo el código, simplemente ejecute en sustuff
lugar.Sin embargo, si necesita usar la salida de
stuff
más de una vez, entonces este enfoquesuele ser mejor que
Incluso si
foo
es asíecho
y obtieneecho "$var"
su código, puede ser mejor mantenerlo de esta manera. Cosas para considerar:var=$(stuff)
stuff
carreras una vez; incluso si el comando es rápido, evitar calcular la misma salida dos veces es lo correcto. O tal vezstuff
tenga otros efectos además de escribir en stdout (por ejemplo, crear un archivo temporal, iniciar un servicio, iniciar una máquina virtual, notificar a un servidor remoto), por lo que no desea ejecutarlo varias veces.stuff
genera resultados dependientes del tiempo o algo aleatorios, puede obtener resultados inconsistentes defoo "$(stuff)"
ybar "$(stuff)"
. Después de quevar=$(stuff)
el valor de$var
es fijo y puede estar segurofoo "$var"
ybar "$var"
obtener un argumento de línea de comando idéntico.En algunos casos, en lugar de
foo "$var"
que desee (necesite) usarfoo $var
, especialmente sistuff
genera múltiples argumentos parafoo
(una variable de matriz puede ser mejor si su shell lo admite). De nuevo, sepa lo que está haciendo. Cuando se trata deecho
la diferencia entreecho $var
yecho "$var"
es lo mismo que entreecho $(stuff)
yecho "$(stuff)"
.* Equivalente ( -ish )?
Dije que
echo "$(stuff)"
es equivalente (-ish) astuff
. Hay al menos dos problemas que hacen que no sea exactamente equivalente:$(stuff)
se ejecutastuff
en una subshell, por lo que es mejor decir queecho "$(stuff)"
es equivalente (-ish) a(stuff)
. Los comandos que afectan el shell en el que se ejecutan, si están en un subshell, no afectan al shell principal.En este ejemplo
stuff
esa=1; echo "$a"
:Compáralo con
y con
Otro ejemplo, comienza con
stuff
sercd /; pwd
:y prueba
stuff
y(stuff)
versiones.echo
No es una buena herramienta para mostrar datos no controlados . Esto de loecho "$var"
que estábamos hablando debería haber sidoprintf '%s\n' "$var"
. Pero como la pregunta mencionaecho
y dado que la solución más probable es no usarlaecho
en primer lugar, decidí no presentarlaprintf
hasta ahora.stuff
o(stuff)
intercalará la salida stdout y stderr, mientrasecho $(stuff)
imprimirá toda la salida stderr destuff
(que se ejecuta primero), y solo luego la salida stdout digerida porecho
(que se ejecuta al final).$(…)
elimina cualquier nueva línea final y luego laecho
agrega de nuevo. Entoncesecho "$(printf %s 'a')" | xxd
da una salida diferente queprintf %s 'a' | xxd
.Algunos comandos (
ls
por ejemplo) funcionan de manera diferente dependiendo de si la salida estándar es una consola o no; asíls | cat
que no hace lo mismols
. Del mismo modoecho $(ls)
funcionará de manera diferente quels
.Dejando de
ls
lado, en un caso general, si tiene que forzar este otro comportamiento, entoncesstuff | cat
es mejorecho $(ls)
oecho "$(ls)"
porque no desencadena todos los otros problemas mencionados aquí.Posiblemente diferente estado de salida (mencionado para completar la respuesta de esta wiki; para más detalles vea otra respuesta que merece crédito).
fuente
stuff
camino se intercalarástdout
y generarástderr
, mientrasecho `stuff`
que imprimirá toda lastderr
salidastuff
, y solo entonces lastdout
salida.echo $(stuff)
puedeecho "$(stuff)"
meterte en muchos más problemas como si no quisieras englobar y expandirte explícitamente.$(…)
elimina cualquier nueva línea final y luego laecho
agrega de nuevo. Entoncesecho "$(printf %s 'a')" | xxd
da una salida diferente queprintf %s 'a' | xxd
.ls
por ejemplo) funcionan de manera diferente dependiendo de si la salida estándar es una consola o no; asíls | cat
que no hace lo mismols
. Y, por supuestoecho $(ls)
, funcionará de manera diferente quels
.Otra diferencia: el código de salida del subconjunto se pierde, por lo que
echo
se recupera el código de salida de .fuente
$?
será el código de retorno deecho
(paraecho $(stuff)
) en lugar del códigoreturn
editado porstuff
. Lastuff
funciónreturn 1
(código de salida), pero laecho
establece en "0" independientemente del código de retorno destuff
. Todavía debería estar en la respuesta.