(...)和{...}如何在bash中使用管道与子shell创建交互?

vbe*_*nar 5 bash

我试图理解使用圆括号和大括号的shell子进程调用之间的区别.我认为大括号不会启动子进程,但似乎它们确实启动了一个子进程.

#!/bin/sh

a=1
b=1

( a=2; ) | ( a=3; )
{ b=2; } | { b=3; }

echo "a=$a"
echo "b=$b"
Run Code Online (Sandbox Code Playgroud)

打印此脚本

a=1
b=1
Run Code Online (Sandbox Code Playgroud)

所以似乎所有调用都在子进程内运行.在这种背景下他们之间有什么区别吗?我明白,如果我会用&&||,则{..}不会启动子,但我想了解的管道是如何工作的.

Cha*_*ffy 5

为了证明它是生成子shell的管道本身,并且花括号不会改变这种方式:

#!/bin/bash

echo "Base: $BASHPID"
( echo "In (): $BASHPID" )   # This will differ from the base
{ echo "In {}: $BASHPID"; }  # This will match the base

# In bash, these will both differ from the base
echo "Pipeline, default config:"
{ echo " X: $BASHPID" >&2; } | { echo " Y: $BASHPID" >&2; }

# This is exactly the same without the {}s
echo "Pipeline, no {}s, default config:"
echo " X: $BASHPID" >&2 | echo " Y: $BASHPID" >&2

# Only the former will differ from the base if running a new enough bash
shopt -s lastpipe
echo "Pipeline, lastpipe enabled:"
{ echo " X: $BASHPID" >&2; } | { echo " Y: $BASHPID" >&2; }
Run Code Online (Sandbox Code Playgroud)

使用bash 4.3在本地运行,我得到:

Base: 82811
In (): 82812
In {}: 82811
Pipeline, default config:
 X: 82813
 Y: 82814
Pipeline, no {}s, default config:
 X: 82815
 Y: 82816
Pipeline, lastpipe enabled:
 Y: 82811
 X: 82817
Run Code Online (Sandbox Code Playgroud)

请注意,由于所有管道组件同时运行,因此没有定义先排序XY将首先发出输出的顺序; 但是,lastpipe启用后,最后一个管道组件将在已经启动并运行的shell中调用(不需要fork()从主进程中删除),这稍微修改了谁先写入stdout的可能性.