流程替换的惯用用法
Idiomatic use of process substitution
我从 Bash 的手册页中学习了 Bash 进程替换。不幸的是,我对该功能的不熟练使用很丑陋。
DEV=<(some commands that produce lines of data) && {
while read -u ${DEV##*/} FIELD1 FIELD2 FIELD3; do
some commands that consume the fields of a single line of data
done
}
熟练的程序员有其他方法可以做到这一点吗?
如果需要可执行样本,试试这个:
DEV=<(echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n") && {
while read -u ${DEV##*/} FIELD1 FIELD2 FIELD3; do
echo "$FIELD1 lies in $FIELD2 County, $FIELD3."
done
}
示例输出:
Cincinnati lies in Hamilton County, Ohio.
Atlanta lies in Fulton County, Georgia.
在我的实际应用中,"some commands"比较复杂,但上面的例子抓住了问题的本质。
需要进程替换 <()
。进程替换的替代方法无济于事。
使用运算符 <
.
重定向到循环的标准输入
while read city county state; do
echo "$city lies in $county County, $state."
done < <(echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n")
输出:
Cincinnati lies in Hamilton County, Ohio.
Atlanta lies in Fulton County, Georgia.
请注意,在此示例中,管道也能正常工作。
echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n" |
while read city county state
do
echo "$city lies in $county County, $state."
done
另外,环境变量(如PATH
)和其他特殊变量(如RANDOM
)应保留大写变量名。描述性的变量名总是好的。
几乎没有可移植的选择。 'right' 的选择取决于具体情况。特别是,它取决于生成输入数据的时间和输入的大小。特别是:
如果处理数据需要很多时间,您希望在数据生成和 'while' 循环之间进行并行处理。这将导致增量处理,并且在开始输出数据处理之前不必等待所有输入数据处理。
如果输入非常大(并且不适合 shell 变量),您可能别无选择,只能强制使用实际管道。当数据是二进制、Unicode 或类似数据时也是如此 - 其中 bash 变量将不起作用。
映射到原始问题 - PRODUCE = echo Cincinnati ...
,以及 CONSUME - echo "$city ..."
对于简单的情况(小输入,快速 produce/consume),下面的方法将起作用。 Bash 将 运行 他们顺序地:生产然后消费。
while read ... ; do
CONSUME
done <<< "$(PRODUCE)"
对于复杂的情况(输入大,或者生产消费慢),可以使用下面的方法来请求并行执行
while read ... ; do
CONSUME
done < <(PRODUCE)
对于复杂(循环、条件等)或长(多行)的 PRODUCE 代码,考虑将其移动到一个函数中,而不是将它们内联到循环命令中。
function produce {
PRODUCE
}
while read ... ; do
CONSUME
done < <(produce)
我从 Bash 的手册页中学习了 Bash 进程替换。不幸的是,我对该功能的不熟练使用很丑陋。
DEV=<(some commands that produce lines of data) && {
while read -u ${DEV##*/} FIELD1 FIELD2 FIELD3; do
some commands that consume the fields of a single line of data
done
}
熟练的程序员有其他方法可以做到这一点吗?
如果需要可执行样本,试试这个:
DEV=<(echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n") && {
while read -u ${DEV##*/} FIELD1 FIELD2 FIELD3; do
echo "$FIELD1 lies in $FIELD2 County, $FIELD3."
done
}
示例输出:
Cincinnati lies in Hamilton County, Ohio.
Atlanta lies in Fulton County, Georgia.
在我的实际应用中,"some commands"比较复杂,但上面的例子抓住了问题的本质。
需要进程替换 <()
。进程替换的替代方法无济于事。
使用运算符 <
.
while read city county state; do
echo "$city lies in $county County, $state."
done < <(echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n")
输出:
Cincinnati lies in Hamilton County, Ohio.
Atlanta lies in Fulton County, Georgia.
请注意,在此示例中,管道也能正常工作。
echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n" |
while read city county state
do
echo "$city lies in $county County, $state."
done
另外,环境变量(如PATH
)和其他特殊变量(如RANDOM
)应保留大写变量名。描述性的变量名总是好的。
几乎没有可移植的选择。 'right' 的选择取决于具体情况。特别是,它取决于生成输入数据的时间和输入的大小。特别是:
如果处理数据需要很多时间,您希望在数据生成和 'while' 循环之间进行并行处理。这将导致增量处理,并且在开始输出数据处理之前不必等待所有输入数据处理。
如果输入非常大(并且不适合 shell 变量),您可能别无选择,只能强制使用实际管道。当数据是二进制、Unicode 或类似数据时也是如此 - 其中 bash 变量将不起作用。
映射到原始问题 - PRODUCE = echo Cincinnati ...
,以及 CONSUME - echo "$city ..."
对于简单的情况(小输入,快速 produce/consume),下面的方法将起作用。 Bash 将 运行 他们顺序地:生产然后消费。
while read ... ; do
CONSUME
done <<< "$(PRODUCE)"
对于复杂的情况(输入大,或者生产消费慢),可以使用下面的方法来请求并行执行
while read ... ; do
CONSUME
done < <(PRODUCE)
对于复杂(循环、条件等)或长(多行)的 PRODUCE 代码,考虑将其移动到一个函数中,而不是将它们内联到循环命令中。
function produce {
PRODUCE
}
while read ... ; do
CONSUME
done < <(produce)