&&

&&

让我们看下面的两行,它们给出了两个不同的结果。

p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ |  pwd) ; echo $p

两者有何不同?

答案1

p=$(cd ~ && pwd)

  • 命令替换 ,$()在子 shell 中运行

  • cd ~将目录更改为~(您的主目录),如果cd成功(&&),则pwd在 STDOUT 上打印目录名称,因此保存的字符串p将是您的主目录,例如/home/foobar

p=$(cd ~ | pwd)

  • 再次$()生成一个子shell

  • 两边的命令|在各自的子 shell 中运行(并且两者同时启动)

  • cd ~是在子 shell 中完成的,并且pwd分离子外壳

  • pwd因此,您只能从运行命令的位置获得 ie 的 STDOUT ,这可以是您可以想象的任何目录,因此p将包含调用命令的目录名称,而不是您的主目录

答案2

核心问题是如何将操作符&&|两个命令连接起来。

通过退出代码连接&&命令。|通过文件描述符(stdin、stdout)连接两个命令。

我们先简化一下。我们可以删除分配并编写:

echo $(cd ~ && pwd)
echo $(cd ~ | pwd)

我们甚至可以删除命令执行子 shell 来分析:

$ cd ~ && pwd
$ cd ~ | pwd

&&

如果我们更改提示以显示执行命令的目录,例如PS1='\w\$ ',我们将看到以下内容:

/tmp/user$ cd ~ && pwd
/home/user
~$ 
  • 该命令cd ~将“当前目录”更改为正在执行该命令的实际用户的主目录 ( /home/user)。
  • 由于命令的结果是成功(退出代码0),执行&&之后的下一个命令
  • 并打印“当前工作目录”。
  • 运行的 shell 已更改pwd~,如 的提示符所示~$

如果由于某种原因(目录不存在、权限阻止读取目录)导致目录更改不成功(退出代码不为 0),则不会执行下一个命令。

例子:

/tmp/user$ false && pwd
/tmp/user$ _ 

退出代码 1 会false阻止执行下一个命令。

因此,“命令 1”的退出代码会影响“命令 2”。

现在,整个命令的效果:

/tmp/user$ echo $(cd ~ && pwd)
/home/user
/tmp/user$ _

目录已更改,但在子 shell 内$(…),会打印更改的目录/home/user,但会在子 shell 关闭时立即丢弃。 pwd 返回到初始目录 ( /tmp/user)。

|

发生的情况是这样的:

/tmp/user$ cd ~ | pwd
/tmp/user
/tmp/user$ _

元字符|(不是真正的运算符)指示 shell 创建所谓的“管道”,(在 bash 中)管道 ( |) 每一侧的每个命令都设置在每个自己的子 shell 内,首先是右侧命令,然后是左边的命令。右侧命令的输入文件描述符 ( /dev/stdin) 连接到输出描述符 ( /dev/stdout),然后启动两个命令并进行交互。左侧命令 ( cd -) 没有输出,右侧命令 ( pwd) 也不接受输入。因此,每个 shell 都在自己的子 shell 内独立运行。

  • 更改cd ~一个 shell 的 pwd。
  • 打印pwd另一个子 shell 的(完全独立的)密码。

当管道结束时,每个 shell 上的更改都会被丢弃,外部子 shell 没有更改 pwd。

这就是为什么这两个命令仅通过“文件描述符”连接。
在这种情况下,没有发送任何内容,也没有读取任何内容。

整个命令:

$ echo "$(cd ~ | pwd)"

只会打印执行命令的目录。

答案3

我不确定你的意思是不是“|”或“||”在你的第二种情况下。

'|'在 shell 中,将一个命令的输出传输到另一个命令的输入 - 常见的用例类似于: curl http://abcd.com/efgh | grep ijkl 即运行一个命令,然后使用另一个命令来处理命令的输出。

在您给出的示例中,这是相当无意义的,因为“cd”通常不会生成任何输出,而“pwd”则不需要任何输入。

'&&' 和 '||'不过是合作伙伴的命令。它们的设计方式与大多数语言中的逻辑“与”和“或”运算符的使用方式相同。然而,所执行的优化赋予它们特定的行为,即 shell 编程范例。

要确定逻辑“与”运算的结果,您只需在第一个条件成功时评估第二个条件 - 如果第一个条件失败,则总体结果将始终为 false。

要确定逻辑“或”运算的结果,只需在第一个条件失败时评估第二个条件 - 如果第一个条件成功,则总体结果将始终为真。

所以,在shell中,如果有的话,只有在完成并返回成功的结果代码command1 && command2 command2时才会被执行。command1如果您有,command1 || command2 command2则将在完成时执行command1,如果command1返回失败代码。

另一个常见的范例是command1测试命令 - 这会生成单行 if/then 语句 - 例如:

[ "$VAR" = "" ] && VAR="Value if empty"

如果变量当前为空,则这是一种(冗长的)为其赋值的方法。

Stack Exchange 上的其他地方有许多使用此过程的示例

相关内容