让我们看下面的两行,它们给出了两个不同的结果。
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 上的其他地方有许多使用此过程的示例