我遇到了我正在做的情况:
outputStuff |
filterStuff |
transformStuff |
doMoreStuff |
endStuff > endFile
我希望能够以如下方式插入一些调试跟踪内容:
tee debugFile.$((debugNum++)) |
但显然管道会创建子壳,所以我想这样做。
exec 5< <(seq 1 100)
outputStuff |
tee debugFile.$(read -u 5;echo $REPLY;) |
filterStuff |
tee debugFile.$(read -u 5;echo $REPLY;) |
transformStuff |
tee debugFile.$(read -u 5;echo $REPLY;) |
doMoreStuff |
endStuff > endFile
即,我希望我插入的调试行是相同的,所以我不必担心踩到各种东西。 read / REPLY回声看起来真的很难看。我想我可以包装一个函数..但有一种方法可以从文件描述符读取一行到stdout而不关闭fd (就像一个头-1将关闭fd是我的头-1&lt;&amp; 3)
答案 0 :(得分:1)
将所有读取放在单个复合语句中,并将描述符5中的输入重定向到 。
{ outputStuff | tee debugFile.$(read -u 5;echo $REPLY;) |
filterStuff | tee debugFile.$(read -u 5;echo $REPLY;) |
transformStuff | tee debugFile.$(read -u 5;echo $REPLY;) |
doMoreStuff |
endStuff
} 5< <(seq 1 100) > endFile
现在,文件描述符5打开一次(并关闭一次),每次调用read
都会从该描述符中获取连续的行。
(您也可以稍微简化一下;除非您通过键盘向outputStuff
提供输入,否则似乎不需要使用文件描述符5而不是标准输入,因为只有{{ 1}}正在从标准输入读取。所有其他程序都通过管道读取它们的标准输入。)
答案 1 :(得分:1)
我尝试了几件事,但最后@Etan Reisner(无意中)向我证明,即使有办法做你所问的(聪明的,Etan),它也不是你真正想要的。如果你想确保按顺序读回数字,那么读取必须被序列化,而管道中的命令则不是。
实际上,这也适用于您的原始方法,因为命令替换是在子壳中执行的。我认为你可以这样做,但是:
debugum=1
eval "
outputStuff |
tee debugFile.$((debugNum++)) |
filterStuff |
transformStuff |
doMoreStuff |
tee debugFile.$((debugNum++)) |
endStuff > endFile
"
这样,在启动任何命令之前,所有替换都由字符串上的父shell执行。
答案 2 :(得分:0)
以均匀填充你的号码为代价,你可以用dd做到这一点,虽然你最终没有找到一个更好看的命令来解决你的麻烦。 =)
exec 5< <(seq -w 10 -1 1)
echo -n |
{ echo "d 1:$(dd bs=1 count=3 2>/dev/null <&5)"; cat; } |
{ echo "d 2:$(dd bs=1 count=3 2>/dev/null <&5)"; cat; } |
{ echo "d 3:$(dd bs=1 count=3 2>/dev/null <&5)"; cat; } |
{ echo "d 4:$(dd bs=1 count=3 2>/dev/null <&5)"; cat; } |
cat
您也可以使用read
read -u 5 a;echo $a
更短的变量,但只能保存两个字符。
答案 3 :(得分:0)
这是一种根本不需要seq
的方法:
定义一个递归构造管道的函数。
buildWithDebugging() {
local -a nextCmd=( )
local debugNum=$1; shift
while (( $# )) && [[ $1 != '|' ]]; do
nextCmd+=( "$1" )
shift
done
if (( ${#nextCmd[@]} )); then
"${nextCmd[@]}" \
| tee "debugFile.$debugNum" \
| buildWithDebugging "$((debugNum + 1))" "$@"
else
cat # noop
fi
}
......并且,使用它:
buildWithDebugging 0 \
outputStuff '|'
filterStuff '|'
transformStuff '|'
doMoreStuff '|'
endStuff > endFile
更安全的版本将使用以Pascal字符串而不是C字符串形式完成的管道组件 - 也就是说,而不是使用文字|
,在每个命令字符串前面加上其长度: / p>
buildWithDebugging 0 \
1 outputStuff
3 filterStuff filterArg filterSecondArg
2 transformStuff filterArg
1 doMoreStuff
endStuff > endFile
对读者来说,建立这个应该是一个完全无足轻重的练习。 :)