考虑以下将终端程序输出的列数据转换为 JSON 的函数的简化版本...
旁注:第二个例子可能读起来更快,以理解我的潜在问题。
function filter_proc () {
local save=$(tempfile)
local var1=''
local var2=''
local var3=''
local var4=''
cat > $save
read var1 var2 var3 var4 < <(
cat $save | grep "qualifying-line" | awk '{print $3,$4,$5,$7}'
);
calculated=$((var1+var3-1))
cat <<JSON
{
"header": {
"var1": "$var2",
"var4": "$var4"
JSON
echo -n " },"
local state="column1";
local count=0;
for field in $(
echo $(
cat $save | perl -ne 'print unless 1../^MySearchTerm /'| sed -e '/^$/,$d'
echo -eod-
) ) ; do
case $field in
-eod-)
echo -n '"count": '
echo "$count }'
break;
;;
*)
echo -n '"'
echo -n "$state"
echo -n '": "'
echo -n "$field"
echo -n '",'
case $state in
"column1")
state="column2"
count=$((count+1))
;;
"column2")
state="this_is_col3"
;;
"this_is_col3")
state="the_fourth_column"
;;
"the_fourth_column")
state="column1"
;;
esac;
;;
esac;
done;
rm $save
}
我试图避免使用临时文件(此示例中为 ($save)。问题是我无法读取 std_in 两次。我尝试使用 tee 来解决这个问题,但看起来使用 tee 的每个子进程都是同时发生的,所以我无法保证处理输出的顺序,正如这个愚蠢的例子所示:
time (echo hello | tee >( sleep 5 ; echo -n "first:" ; cat; ) >(sleep 3 ; echo -n "second:" ; cat;) | ( echo -n "piped:"; cat ;) ; )
其输出为:(等待约 5 秒后 - 如果当前未运行,则可能不是 8 秒)
piped:hello second:hello first:hello real 0m5.030s user 0m0.010s sys 0m0.000s
确保(在第二个例子中)获得这个结果的最佳方法是什么?
first:hello second:hello piped:hello real 0m5.030s user 0m0.010s sys 0m0.000s
请记住,我很高兴实际得到答案的时间是 8 秒。我只是不想使用临时文件,因为我不想写入磁盘(当然,我可以设置一个 RAM 驱动器,但那完全是另一个问题)
答案1
如果您还为您的 bash 脚本提供了输入和期望/实际输出示例,那就更好了,但我还是会尝试一下。
在第二个示例中,您绝对会获得 piped/second/first,并且您无法获得其他任何内容。second 和 first 的执行是并发的,但是first
的休眠时间比 长second
,因此它是这两个中最后一个执行的。piped
由于它在主管道中,因此会立即执行,然后输出其余部分。tee
首先发送一个简单的 hello,然后它获得 sleep 3 second
,然后是 sleep 5 first
。
在一个严肃的专业示例中,我会选择以下任一方式:
使用 python 将列读入数据结构并按所需顺序直接输出 json
在读入所有内容时,给所有内容加上一个数字前缀,然后通过管道传输
sort -n
(sort 可能会使用临时文件,但除非真的有必要,否则不会使用)。但是,这无法很好地与 json 配合使用。通过在原始列输入前添加数字(
nl
)或时间戳作为前缀来过滤原始列输入,并将其集成到 json 中。
答案2
好吧,这个解决方案对于我最初尝试做的事情来说有点过度了,但我还是将它发布在这里以防它有用。我最终使用了命名管道并通过 tee 将它们链接起来。花了一些时间弄清楚如何将其布局得美观,但它就在这里。我最初的方法使用了 1 个临时文件,而这个方法使用了 3 个命名管道,所以这有点过度设计了。但它可能在其他地方有用。
编辑:更新以让其使用临时文件。
#create a temp folder using whatever method we have available
function tempfolder () {
local folder;
which mktemp >/dev/null && folder=$(mktemp -d) ||
(which tempfile >/dev/null && folder=$(tempfile) && rm $folder && mkdir $folder) ||
(folder="/tmp/$(basename $0)_$$" && mkdir $folder)
echo $folder
}
function pipename() {
echo $1/pipe${2}
}
function createPipes() {
local pib=$(tempfolder);
while [[ "$1" != "" ]] ; do
p=$(pipename $pib $1)
[[ ! -p $p ]] && mkfifo $p
shift
done;
echo $pib;
}
function closePipes() {
local pib="$1";
[[ $pib = "" ]] && exit;
rm -r $pib
}
function tester () {
local pb=$(createPipes 1 2 3);
tee >(
echo "task1:fetching" >&2
read greeting recipient random verbage greeter;
echo "task1:thinking" >&2
sleep 5;
echo "task1:replying" >&2
echo "task1:hello $greeter. nice to meet you. but my name is not $recipient." > $(pipename $pb 1)
echo "task1:i'm done" >&2
) >(
echo "task2:fetching" >&2
read Mr Clinton Needs A Dictionary;
echo "task2:thinking" >&2
sleep 3;
echo "task2:replying" >&2
echo "task2:It depends on what the meaning of the word $A is."> $(pipename $pb 2)
echo "task2:i'm done" >&2
) >(
echo "task3:fetching" >&2
read I Read random words and comment;
echo "task3:$random is a random word" > $(pipename $pb 3)
echo "task3:i'm done" >&2
) | (
cat $(pipename $pb 1) $(pipename $pb 2) $(pipename $pb 3);
closePipes $pb 1 2 3;
)
}
time (echo hello world it is me - thanks | tester;)