Usé uno de los siguientes
echo $(stuff)
echo `stuff`
(donde stuffes, por ejemplo pwd, o dateo 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
stuffsería más probable que funcione para usted.Respuesta completa
Lo que pasa
Cuando corres
foo $(stuff), esto es lo que sucede:stuffcarreras;$(stuff)en la invocación defoo;fooejecuta, sus argumentos de línea de comando obviamente dependen de lo questuffdevuelve.Este
$(…)mecanismo se llama "sustitución de comando". En su caso, el comando principal es elechoque básicamente imprime sus argumentos de línea de comando en stdout. Entonces, cualquier cosa questuffintente imprimir en stdout es capturada, pasadaechoe impresa en stdout porecho.Si desea que la salida
stuffse 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
stuffyecho $(stuff)no es exactamente equivalente. Esto último significa llamar al operador split + glob en la salida destuffcon 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
stuffdivida + 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 sustufflugar.Sin embargo, si necesita usar la salida de
stuffmás de una vez, entonces este enfoquesuele ser mejor que
Incluso si
fooes asíechoy obtieneecho "$var"su código, puede ser mejor mantenerlo de esta manera. Cosas para considerar:var=$(stuff)stuffcarreras una vez; incluso si el comando es rápido, evitar calcular la misma salida dos veces es lo correcto. O tal vezstufftenga 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.stuffgenera resultados dependientes del tiempo o algo aleatorios, puede obtener resultados inconsistentes defoo "$(stuff)"ybar "$(stuff)". Después de quevar=$(stuff)el valor de$vares 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 sistuffgenera 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 deechola diferencia entreecho $varyecho "$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 ejecutastuffen 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
stuffesa=1; echo "$a":Compáralo con
y con
Otro ejemplo, comienza con
stuffsercd /; pwd:y prueba
stuffy(stuff)versiones.echoNo 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 mencionaechoy dado que la solución más probable es no usarlaechoen primer lugar, decidí no presentarlaprintfhasta ahora.stuffo(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 laechoagrega de nuevo. Entoncesecho "$(printf %s 'a')" | xxdda una salida diferente queprintf %s 'a' | xxd.Algunos comandos (
lspor ejemplo) funcionan de manera diferente dependiendo de si la salida estándar es una consola o no; asíls | catque no hace lo mismols. Del mismo modoecho $(ls)funcionará de manera diferente quels.Dejando de
lslado, en un caso general, si tiene que forzar este otro comportamiento, entoncesstuff | cates 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
stuffcamino se intercalarástdouty generarástderr, mientrasecho `stuff`que imprimirá toda lastderrsalidastuff, y solo entonces lastdoutsalida.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 laechoagrega de nuevo. Entoncesecho "$(printf %s 'a')" | xxdda una salida diferente queprintf %s 'a' | xxd.lspor ejemplo) funcionan de manera diferente dependiendo de si la salida estándar es una consola o no; asíls | catque 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
echose recupera el código de salida de .fuente
$?será el código de retorno deecho(paraecho $(stuff)) en lugar del códigoreturneditado porstuff. Lastufffunciónreturn 1(código de salida), pero laechoestablece en "0" independientemente del código de retorno destuff. Todavía debería estar en la respuesta.