@heemayl Obrigado. Você pode extrair as diferenças no meu caso? Obrigado.
Nam G VU
1
Dica: Os comandos de ambos os lados da |execução em subshells.
heemayl
Respostas:
21
Em p=$(cd ~ && pwd):
A substituição do comando $(), é executada em um subshell
cd ~altera o diretório para ~(sua casa), se cdfor bem-sucedido ( &&), pwdimprime o nome do diretório em STDOUT; portanto, a sequência salva pserá o seu diretório inicial, por exemplo/home/foobar
Em p=$(cd ~ | pwd):
Novamente $()gera um subshell
Os comandos dos dois lados da |execução nos respectivos subshells (e ambos começam ao mesmo tempo)
isso cd ~é feito em um subshell e pwdem um subshell separado
para que você obtenha apenas o STDOUT, pwdou seja, de onde você executa o comando, este pode ser qualquer diretório que você possa imaginar; portanto p, conterá o nome do diretório de onde o comando é chamado, não o diretório inicial
Qual é o propósito do canal entre os comandos? cd ~não produz nenhuma saída e pwdnão lê nenhuma entrada.
Barmar
O segundo comando é essencialmente equivalente, (cd ~);p=$(pwd)não é?
Barmar
@ Barmar Sim, é o que a OP usou, e só estou explicando isso para ele.
amigos estão dizendo sobre heemayl
6
A questão principal é como os operadores &&e |conectam os dois comandos.
O &&conecta os comandos através do código de saída. O |conecta os dois comandos através dos descritores de arquivo (stdin, stdout).
Vamos simplificar primeiro. Podemos remover a tarefa e escrever:
echo $(cd ~&& pwd)
echo $(cd ~| pwd)
Podemos até remover o sub-shell de execução de comando para analisar isso:
$ cd ~&& pwd
$ cd ~| pwd
&&
Se mudarmos o prompt para mostrar o diretório em que os comandos são executados, algo como PS1='\w\$ ', veremos isso:
/tmp/user$ cd ~&& pwd
/home/user
~$
O comando cd ~alterou o "diretório atual" para a página inicial do usuário real que está executando o comando ( /home/user).
Como o resultado do comando foi bem-sucedido (código de saída 0), o próximo comando após o && é executado
E o "diretório de trabalho atual" é impresso.
O shell em execução mudou pwdpara ~como é mostrado pelo prompt de ~$.
Se a alteração do diretório não foi bem-sucedida (código de saída não 0) por algum motivo (o diretório não existe, as permissões bloqueiam a leitura do diretório), o próximo comando não será executado.
Exemplo:
/tmp/user$ false && pwd
/tmp/user$ _
O código de saída 1 de falseimpede a execução do próximo comando.
Portanto, o código de saída do "comando 1" é o que afeta o "comando 2".
O diretório foi alterado, mas dentro de um sub shell $(…), o diretório alterado é impresso /home/user, mas é imediatamente descartado quando o sub shell é fechado. O pwd retorna para o diretório inicial ( /tmp/user).
|
Isto é o que acontece:
/tmp/user$ cd ~| pwd
/tmp/user
/tmp/user$ _
O meta-caractere |(não um operador verdadeiro) sinaliza ao shell para criar o que é chamado de "Pipe", (no bash) cada comando em cada lado do pipe ( |) é definido dentro de cada sub-shell, primeiro o lado direito comando, então, o esquerdo. O descritor do arquivo de entrada ( /dev/stdin) do comando right é conectado ao descritor de saída ( /dev/stdout) e, em seguida, ambos os comandos são iniciados e deixados para interagir. O comando esquerdo ( cd -) não tem saída e, também, o comando direito ( pwd) não aceita entrada. Portanto, cada um roda independentemente dentro de cada subcasca.
O cd ~altera o pwd de um shell.
Ele pwdimprime a senha (completamente independente) da outra subcasca.
As alterações em cada invólucro são descartadas quando o tubo termina, o sub-invólucro externo não alterou a senha.
É por isso que os dois comandos são conectados apenas por "descritores de arquivo".
Nesse caso, não há nada enviado e nada lido.
Todo o comando:
$ echo "$(cd ~ | pwd)"
Apenas imprimirá o diretório em que o comando foi executado.
Não tenho certeza se você quis dizer '|' ou '||' no seu segundo caso.
'|' em um shell canaliza a saída de um comando para a entrada de outro - um caso de uso comum é algo como:
curl http://abcd.com/efgh | grep ijkl
ou seja, execute um comando e use outro comando para processar a saída de um comando.
No exemplo que você fornece, é bastante absurdo, pois 'cd' normalmente não gera nenhuma saída e 'pwd' não espera nenhuma entrada.
'&&' e '||' são comandos de parceiros. Eles foram projetados para serem usados da mesma maneira que os operadores lógicos "e" e "ou" na maioria dos idiomas. No entanto, as otimizações executadas fornecem um comportamento específico, que é um paradigma de programação de shell.
Para determinar o resultado de uma operação lógica "e", você só precisa avaliar a segunda condição se a primeira condição for bem-sucedida - se a primeira condição falhar, o resultado geral será sempre falso.
Para determinar o resultado de uma operação lógica "ou", você só precisa avaliar a segunda condição se a primeira condição falhar - se a primeira condição for bem-sucedida, o resultado geral será sempre verdadeiro.
Portanto, no shell, se você tiver, command1 && command2command2será executado apenas quando command1tiver concluído e retornado um código de resultado bem-sucedido. Se você tiver command1 || command2command2, será executado quando command1concluído, se command1retornar um código de falha.
Outro paradigma comum é ter command1um comando de teste - isso gera uma única linha if / then - por exemplo:
[ "$VAR" = "" ] && VAR="Value if empty"
É uma maneira (longa) de atribuir um valor a uma variável se ela estiver vazia no momento.
Existem muitos exemplos do uso desse processo em outro lugar no Stack Exchange
|
execução em subshells.Respostas:
Em
p=$(cd ~ && pwd)
:A substituição do comando
$()
, é executada em um subshellcd ~
altera o diretório para~
(sua casa), secd
for bem-sucedido (&&
),pwd
imprime o nome do diretório em STDOUT; portanto, a sequência salvap
será o seu diretório inicial, por exemplo/home/foobar
Em
p=$(cd ~ | pwd)
:Novamente
$()
gera um subshellOs comandos dos dois lados da
|
execução nos respectivos subshells (e ambos começam ao mesmo tempo)isso
cd ~
é feito em um subshell epwd
em um subshell separadopara que você obtenha apenas o STDOUT,
pwd
ou seja, de onde você executa o comando, este pode ser qualquer diretório que você possa imaginar; portantop
, conterá o nome do diretório de onde o comando é chamado, não o diretório inicialfonte
cd ~
não produz nenhuma saída epwd
não lê nenhuma entrada.(cd ~);p=$(pwd)
não é?A questão principal é como os operadores
&&
e|
conectam os dois comandos.O
&&
conecta os comandos através do código de saída. O|
conecta os dois comandos através dos descritores de arquivo (stdin, stdout).Vamos simplificar primeiro. Podemos remover a tarefa e escrever:
Podemos até remover o sub-shell de execução de comando para analisar isso:
&&
Se mudarmos o prompt para mostrar o diretório em que os comandos são executados, algo como
PS1='\w\$ '
, veremos isso:cd ~
alterou o "diretório atual" para a página inicial do usuário real que está executando o comando (/home/user
).pwd
para~
como é mostrado pelo prompt de~$
.Se a alteração do diretório não foi bem-sucedida (código de saída não 0) por algum motivo (o diretório não existe, as permissões bloqueiam a leitura do diretório), o próximo comando não será executado.
Exemplo:
O código de saída 1 de
false
impede a execução do próximo comando.Portanto, o código de saída do "comando 1" é o que afeta o "comando 2".
Agora, os efeitos de todo o comando:
O diretório foi alterado, mas dentro de um sub shell
$(…)
, o diretório alterado é impresso/home/user
, mas é imediatamente descartado quando o sub shell é fechado. O pwd retorna para o diretório inicial (/tmp/user
).|
Isto é o que acontece:
O meta-caractere
|
(não um operador verdadeiro) sinaliza ao shell para criar o que é chamado de "Pipe", (no bash) cada comando em cada lado do pipe (|
) é definido dentro de cada sub-shell, primeiro o lado direito comando, então, o esquerdo. O descritor do arquivo de entrada (/dev/stdin
) do comando right é conectado ao descritor de saída (/dev/stdout
) e, em seguida, ambos os comandos são iniciados e deixados para interagir. O comando esquerdo (cd -
) não tem saída e, também, o comando direito (pwd
) não aceita entrada. Portanto, cada um roda independentemente dentro de cada subcasca.cd ~
altera o pwd de um shell.pwd
imprime a senha (completamente independente) da outra subcasca.As alterações em cada invólucro são descartadas quando o tubo termina, o sub-invólucro externo não alterou a senha.
É por isso que os dois comandos são conectados apenas por "descritores de arquivo".
Nesse caso, não há nada enviado e nada lido.
Todo o comando:
Apenas imprimirá o diretório em que o comando foi executado.
fonte
Não tenho certeza se você quis dizer '|' ou '||' no seu segundo caso.
'|' em um shell canaliza a saída de um comando para a entrada de outro - um caso de uso comum é algo como:
curl http://abcd.com/efgh | grep ijkl
ou seja, execute um comando e use outro comando para processar a saída de um comando.No exemplo que você fornece, é bastante absurdo, pois 'cd' normalmente não gera nenhuma saída e 'pwd' não espera nenhuma entrada.
'&&' e '||' são comandos de parceiros. Eles foram projetados para serem usados da mesma maneira que os operadores lógicos "e" e "ou" na maioria dos idiomas. No entanto, as otimizações executadas fornecem um comportamento específico, que é um paradigma de programação de shell.
Para determinar o resultado de uma operação lógica "e", você só precisa avaliar a segunda condição se a primeira condição for bem-sucedida - se a primeira condição falhar, o resultado geral será sempre falso.
Para determinar o resultado de uma operação lógica "ou", você só precisa avaliar a segunda condição se a primeira condição falhar - se a primeira condição for bem-sucedida, o resultado geral será sempre verdadeiro.
Portanto, no shell, se você tiver,
command1 && command2
command2
será executado apenas quandocommand1
tiver concluído e retornado um código de resultado bem-sucedido. Se você tivercommand1 || command2
command2
, será executado quandocommand1
concluído, secommand1
retornar um código de falha.Outro paradigma comum é ter
command1
um comando de teste - isso gera uma única linha if / then - por exemplo:[ "$VAR" = "" ] && VAR="Value if empty"
É uma maneira (longa) de atribuir um valor a uma variável se ela estiver vazia no momento.
Existem muitos exemplos do uso desse processo em outro lugar no Stack Exchange
fonte