定期从异步后台脚本中读取输出

时间:2016-09-23 17:49:53

标签: json bash asynchronous ipc

上下文:我正在创建自己的i3-Bar脚本来读取在后台运行的其他(异步)脚本的输出,将它们连接起来,然后将它们echo连接到i3-Bar本身。 / em>的

我传递输出的方式是普通文件,我猜(逻辑上)问题是文件有时会同时读写。重现此行为的最佳方法是暂停计算机,然后将其唤醒 - 我不知道确切的原因,我只能继续我从调试中看到的内容日志文件。

主要代码: 为了清晰起见添加了评论

#!/usr/bin/env bash
cd "${0%/*}";

trap "kill -- -$$" EXIT; #The bg. scripts are on a while [ 1 ] loop, have to kill them.

rm -r ../input/*;
mkdir ../input/; #Just in case.

for tFile in ./*; do
    #Run all of the available scripts in the current directory in the background.
    if [ $(basename $tFile) != "main.sh" ]; then ("$tFile" &); fi;
done;

echo -e '{ "version": 1 }\n['; #I3-Bar can use infinite array of JSON input.

while [ 1 ]; do

    input=../input/*; #All of the scripts put their output in this folder as separate text files

    input=$(sort -nr <(printf "%s\n" $input));

    output="";

    for tFile in $input; do
        #Read and add all of the files to one output string.
        if [ $tFile == "../input/*" ]; then break; fi;
        output+="$(cat $tFile),";
    done;

    if [ "$output" == "" ]; then
        echo -e "[{\"full_text\":\"ERR: No input files found\",\"color\":\"#ff0000\"}],\n";
    else
        echo -e "[${output::-1}],\n";
    fi;

    sleep 0.2s;
done;

示例输入脚本:

#!/usr/bin/env bash
cd "${0%/*}";

while [ 1 ]; do
    echo -e "{" \
        "\"name\":\"clock\"," \
        "\"separator_block_width\":12," \
        "\"full_text\":\"$(date +"%H:%M:%S")\"}" > ../input/0_clock;
    sleep 1;
done;

问题

问题不在于脚本本身,但事实是,i3-Bar收到格式错误的JSON输入( - &gt;解析错误),并终止 - 我稍后会显示此类日志。

另一个问题是,后台脚本应该异步运行,因为有些需要每隔1分钟更新一次nad,等等。所以使用FIFO并不是一个真正的选择,除非我创建一些丑陋低效的hacky东西。

我知道这里需要IPC,但我不知道如何有效地这样做。

随机崩溃的脚本输出 - 唤醒错误看起来相同

[{ "separator_block_width":12, "color":"#BAF2F8", "full_text":"192.168.1.104 "},{ "separator_block_width":12, "color":"#BAF2F8", "full_text":"100%"}],

[{ "separator_block_width":12, "color":"#BAF2F8", "full_text":"192.168.1.104 "},,],

(错误由第二行创建) 如您所见,主脚本尝试读取文件,没有任何输出,但逗号仍然存在 - &gt;格式错误的JSON。

1 个答案:

答案 0 :(得分:1)

立即错误很容易修复:如果相应的文件为空,请不要在output附加条目:

for tFile in $input; do
    [[ $tFile != "../input/*" ]] &&
      [[ -s $tFile ]] &&
      output+="$(<$tFile),"
done

但是这里存在潜在的竞争条件。仅仅因为特定的输入文件存在并不意味着数据已完全写入其中。我会将您的输入脚本更改为类似

#!/usr/bin/env bash
cd "${0%/*}";

while true; do
    o=$(mktemp)
    printf '{"name": "clock", "separator_block_width": 12, "full_text": %(%H:%M:%S)T}\n' > "$o"
    mv "$o" ../input/0_clock
    sleep 1
done

此外,${output%,}是在必要时修剪尾随逗号的更安全的方法。