@heemayl Gracias. ¿Puedes extraer las diferencias en mi caso? Gracias.
Nam G VU
1
Sugerencia: los comandos a cada lado de la |ejecución en subcapas.
heemayl
Respuestas:
21
En p=$(cd ~ && pwd):
La sustitución del comando $(), se ejecuta en una subshell
cd ~cambia el directorio a ~(su inicio), si cdtiene éxito ( &&), pwdimprime el nombre del directorio en STDOUT, por lo tanto, la cadena guardada pserá su directorio de inicio, por ejemplo/home/foobar
En p=$(cd ~ | pwd):
Nuevamente $()genera una subshell
Los comandos en ambos lados de la |ejecución en subcapas respectivas (y ambos comienzan al mismo tiempo)
así cd ~se hace en una subshell y pwden una subshell separada
para que solo obtenga el STDOUT, pwdes decir, desde donde ejecuta el comando, este puede ser cualquier directorio que pueda imaginar, por plo tanto , contendrá el nombre del directorio desde donde se invoca el comando, no su directorio de inicio
¿Cuál es el propósito de la tubería entre los comandos? cd ~no produce ninguna salida y pwdno lee ninguna entrada.
Barmar
El segundo comando es esencialmente equivalente a (cd ~);p=$(pwd)¿no es así?
Barmar
@Barmar Sí, es lo que OP ha usado, y solo se lo estoy explicando.
heemayl
7
El tema central es cómo los operadores &&y |conectan los dos comandos.
El &&conecta los comandos a través del código de salida. El |conecta los dos comandos a través de los descriptores de archivo (stdin, stdout).
Vamos a simplificar primero. Podemos eliminar la tarea y escribir:
echo $(cd ~&& pwd)
echo $(cd ~| pwd)
Incluso podemos eliminar el sub-shell de ejecución de comandos para analizar esto:
$ cd ~&& pwd
$ cd ~| pwd
&&
Si cambiamos la solicitud para mostrar el directorio donde se ejecutan los comandos, algo así PS1='\w\$ ', veremos esto:
/tmp/user$ cd ~&& pwd
/home/user
~$
El comando cd ~cambió el "directorio actual" a la página de inicio del usuario real que está ejecutando el comando ( /home/user).
Como el resultado del comando fue exitoso (código de salida 0), se ejecuta el siguiente comando después de &&
Y se imprime el "directorio de trabajo actual".
El shell en ejecución ha cambiado pwda ~como se muestra en la solicitud de ~$.
Si el cambio de directorio no tuvo éxito (el código de salida no es 0) por alguna razón (el directorio no existe, los permisos bloquean la lectura del directorio), el siguiente comando no se ejecutará.
Ejemplo:
/tmp/user$ false && pwd
/tmp/user$ _
El código de salida de 1 falseimpide la ejecución del siguiente comando.
Por lo tanto, el código de salida del "comando 1" es lo que afecta al "comando 2".
El directorio se modificó, pero dentro de un sub-shell $(…), el directorio modificado se imprime /home/user, pero se descarta inmediatamente cuando el sub-shell se cierra. El pwd vuelve a ser el directorio inicial ( /tmp/user).
El |
Esto es lo que pasa:
/tmp/user$ cd ~| pwd
/tmp/user
/tmp/user$ _
El meta-carácter |(no es un operador verdadero) le indica al shell que cree lo que se llama un "Pipe", (en bash) cada comando en cada lado del pipe ( |) se configura dentro de cada sub-shell, primero el lado derecho comando, entonces, el izquierdo. El descriptor del archivo de entrada ( /dev/stdin) del comando derecho se conecta al descriptor de salida ( /dev/stdout) y luego ambos comandos se inician y se dejan interactuar. El comando izquierdo ( cd -) no tiene salida y, además, el comando derecho ( pwd) no acepta entrada. Por lo tanto, cada uno se ejecuta de forma independiente dentro de cada sub-shell.
El cd ~cambia el pwd de un shell.
El pwdimprime el pwd (completamente independiente) de la otra sub-shell.
Los cambios en cada caparazón se descartan cuando termina la tubería, la subcapa externa no ha cambiado la pwd.
Es por eso que los dos comandos están conectados solo por "descriptores de archivo".
En este caso, no se envía nada y no se lee nada.
Todo el comando:
$ echo "$(cd ~ | pwd)"
Solo imprimirá el directorio donde se ejecutó el comando.
No estoy seguro si quisiste decir '|' o '||' en tu segundo caso.
'|' en un shell canaliza la salida de un comando a la entrada de otro; un caso de uso común es algo como:
curl http://abcd.com/efgh | grep ijkl
es decir, ejecutar un comando y usar otro comando para procesar la salida de un comando.
En el ejemplo que da, es bastante absurdo, ya que 'cd' generalmente no genera ninguna salida y 'pwd' no espera ninguna entrada.
'&&' y '||' son comandos de pareja sin embargo. Están diseñados para usarse de la misma manera que los operadores lógicos "y" y "o" en la mayoría de los idiomas. Sin embargo, las optimizaciones que se realizan les dan un comportamiento específico que es un paradigma de programación de shell.
Para determinar el resultado de una operación lógica "y", solo necesita evaluar la segunda condición si la primera condición tiene éxito; si la primera condición falla, el resultado general siempre será falso.
Para determinar el resultado de una operación lógica "u", solo necesita evaluar la segunda condición si la primera falla; si la primera condición tiene éxito, el resultado general siempre será verdadero.
Entonces, en el shell, si command1 && command2command2solo se ejecutará cuando se command1haya completado y devuelto un código de resultado exitoso. Si lo tiene command1 || command2command2, se ejecutará cuando se command1complete si command1devuelve un código de falla.
Otro paradigma común es tener command1un comando de prueba; esto genera una sola línea si / luego declaración - por ejemplo:
[ "$VAR" = "" ] && VAR="Value if empty"
Es una forma (de largo aliento) de asignar un valor a una variable si actualmente está vacía.
Hay muchos ejemplos del uso de este proceso en otras partes de Stack Exchange
|
ejecución en subcapas.Respuestas:
En
p=$(cd ~ && pwd)
:La sustitución del comando
$()
, se ejecuta en una subshellcd ~
cambia el directorio a~
(su inicio), sicd
tiene éxito (&&
),pwd
imprime el nombre del directorio en STDOUT, por lo tanto, la cadena guardadap
será su directorio de inicio, por ejemplo/home/foobar
En
p=$(cd ~ | pwd)
:Nuevamente
$()
genera una subshellLos comandos en ambos lados de la
|
ejecución en subcapas respectivas (y ambos comienzan al mismo tiempo)así
cd ~
se hace en una subshell ypwd
en una subshell separadapara que solo obtenga el STDOUT,
pwd
es decir, desde donde ejecuta el comando, este puede ser cualquier directorio que pueda imaginar, porp
lo tanto , contendrá el nombre del directorio desde donde se invoca el comando, no su directorio de iniciofuente
cd ~
no produce ninguna salida ypwd
no lee ninguna entrada.(cd ~);p=$(pwd)
¿no es así?El tema central es cómo los operadores
&&
y|
conectan los dos comandos.El
&&
conecta los comandos a través del código de salida. El|
conecta los dos comandos a través de los descriptores de archivo (stdin, stdout).Vamos a simplificar primero. Podemos eliminar la tarea y escribir:
Incluso podemos eliminar el sub-shell de ejecución de comandos para analizar esto:
&&
Si cambiamos la solicitud para mostrar el directorio donde se ejecutan los comandos, algo así
PS1='\w\$ '
, veremos esto:cd ~
cambió el "directorio actual" a la página de inicio del usuario real que está ejecutando el comando (/home/user
).pwd
a~
como se muestra en la solicitud de~$
.Si el cambio de directorio no tuvo éxito (el código de salida no es 0) por alguna razón (el directorio no existe, los permisos bloquean la lectura del directorio), el siguiente comando no se ejecutará.
Ejemplo:
El código de salida de 1
false
impide la ejecución del siguiente comando.Por lo tanto, el código de salida del "comando 1" es lo que afecta al "comando 2".
Ahora, los efectos de todo el comando:
El directorio se modificó, pero dentro de un sub-shell
$(…)
, el directorio modificado se imprime/home/user
, pero se descarta inmediatamente cuando el sub-shell se cierra. El pwd vuelve a ser el directorio inicial (/tmp/user
).El |
Esto es lo que pasa:
El meta-carácter
|
(no es un operador verdadero) le indica al shell que cree lo que se llama un "Pipe", (en bash) cada comando en cada lado del pipe (|
) se configura dentro de cada sub-shell, primero el lado derecho comando, entonces, el izquierdo. El descriptor del archivo de entrada (/dev/stdin
) del comando derecho se conecta al descriptor de salida (/dev/stdout
) y luego ambos comandos se inician y se dejan interactuar. El comando izquierdo (cd -
) no tiene salida y, además, el comando derecho (pwd
) no acepta entrada. Por lo tanto, cada uno se ejecuta de forma independiente dentro de cada sub-shell.cd ~
cambia el pwd de un shell.pwd
imprime el pwd (completamente independiente) de la otra sub-shell.Los cambios en cada caparazón se descartan cuando termina la tubería, la subcapa externa no ha cambiado la pwd.
Es por eso que los dos comandos están conectados solo por "descriptores de archivo".
En este caso, no se envía nada y no se lee nada.
Todo el comando:
Solo imprimirá el directorio donde se ejecutó el comando.
fuente
No estoy seguro si quisiste decir '|' o '||' en tu segundo caso.
'|' en un shell canaliza la salida de un comando a la entrada de otro; un caso de uso común es algo como:
curl http://abcd.com/efgh | grep ijkl
es decir, ejecutar un comando y usar otro comando para procesar la salida de un comando.En el ejemplo que da, es bastante absurdo, ya que 'cd' generalmente no genera ninguna salida y 'pwd' no espera ninguna entrada.
'&&' y '||' son comandos de pareja sin embargo. Están diseñados para usarse de la misma manera que los operadores lógicos "y" y "o" en la mayoría de los idiomas. Sin embargo, las optimizaciones que se realizan les dan un comportamiento específico que es un paradigma de programación de shell.
Para determinar el resultado de una operación lógica "y", solo necesita evaluar la segunda condición si la primera condición tiene éxito; si la primera condición falla, el resultado general siempre será falso.
Para determinar el resultado de una operación lógica "u", solo necesita evaluar la segunda condición si la primera falla; si la primera condición tiene éxito, el resultado general siempre será verdadero.
Entonces, en el shell, si
command1 && command2
command2
solo se ejecutará cuando secommand1
haya completado y devuelto un código de resultado exitoso. Si lo tienecommand1 || command2
command2
, se ejecutará cuando secommand1
complete sicommand1
devuelve un código de falla.Otro paradigma común es tener
command1
un comando de prueba; esto genera una sola línea si / luego declaración - por ejemplo:[ "$VAR" = "" ] && VAR="Value if empty"
Es una forma (de largo aliento) de asignar un valor a una variable si actualmente está vacía.
Hay muchos ejemplos del uso de este proceso en otras partes de Stack Exchange
fuente