击操纵和排序通过循环阵列上的文件内容

问题描述 投票:1回答:1

Purpose

创建一个bash脚本,它通过一定的命令循环,并保存每个命令的输出(它们只打印数字)到一个文件中(我想最好的办法是将它们保存在一个文件?)与相邻的他们的时间(UNIX时间)输出等下次我们运行脚本,它通过再次循环,我们可以使用这些存储的值,看看是否有没有在过去一小时内的命令输出的任何变化。

Example output

# ./script
command1 123123
command2 123123

Important notes

  • 大约有200命令该脚本会通过循环。
  • 我们还会在未来的新命令,因此该脚本将检查这个命令,在保存文件存在。如果它已经存在,只是在最后一小时内进行比较,看是否自上次保存文件的数量发生了变化。如果不存在的话,将其保存到文件中,所以我们可以用它下一次比较。
  • 该脚本将运行可能是因为命令增加/减少/改变不同的命令顺序。因此,如果只是这样的现在;
# ./script
command1 123123
command2 123123

你在将来增加一个第三个命令,该命令可能会发生变化(这也不是一定的它的下面是什么样的格局),例如:

# ./script
command1 123123
command3 123123
command2 123123

所以我们不能,例如,通过线与在这种情况下,阅读它行,我相信最好的办法是将它们与command*名称进行比较。

Structure for stored values

我对存储的值假定结构是这样的(没有坚持这个寿);

command1 123123 unixtime
command2 123123 unixtime

About the said commands

我叫commands的东西基本上这是在/usr/local/bin/一个可以直接运行在外壳上自己的名字,像command1 getnumber访问运行的应用程序,它会打印你的号码。

由于命令位于/usr/local/bin/和以下类似的模式,我首先通过/usr/local/bin/command*循环。见下文。

commands=`find /usr/local/bin/ -name 'command*'`

for i in $commands; do
    echo "$i" "`$i getnumber`"
done

因此通过与command启动和运行command* getnumber为每一个所有文件,这将打印出我们所需要的这个数字将循环。

现在,我们需要将这些值存储在一个文件给他们下一次比较,我们运行命令。

抓住:

我们甚至可以运行该脚本每隔几分钟,但我们只需要当值(数字)没有在最后一刻改变了汇报。

该脚本将列表中的号码每次运行它的时候,我们可以添加一个造型那些谁是不是在最后一刻改变了弹出出来的眼睛,也许像加入了红色到他们吗?

Attempt number #1

所以这是我第一次尝试建立这个脚本。这里是什么样子;

#!/bin/bash

commands=`find /usr/local/bin/ -name 'command*'`
date=`date +%s`

while read -r command number unixtime; do
    for i in $commands; do
        current_block_count=`$i getnumber`
        if [[ $command = $i ]]; then
            echo "$i exists in the file, checking the number changes within last hour" # just for debugging, will be removed in production
            if (( ($date-$unixtime)/60000 > 60 )); then
                if (( $number >= $current_number_count )); then
                    echo "There isn't a change within the last hour, this is a problem!" # just for debugging, will be removed in production
                    echo -e "$i" "`$i getnumber`" "/" "$number" "\e[31m< No change within last hour."
                else
                    echo "$i" "`$i getnumber`"
                    echo "There's a change within the last hour, we're good." # just for debugging, will be removed in production
                    # find the line number of $i so we can change it with the new output
                    line_number=`grep -Fn '$i' outputs.log`
                    new_output=`$i getnumber`
                    sed -i "$line_numbers/.*/$new_output/" outputs.log
                fi
            else
                echo "$i" "`$i getnumber`"
                # find the line number of $i so we can change it with the new output
                line_number=`grep -Fn '$i' outputs.log`
                output_check="$i getnumber; date +%s"
                new_output=`eval ${output_check}`
                sed -i "$line_numbers/.*/$new_output/" outputs.log
            fi
        else
            echo "$i does not exists in the file, adding it now" # just for debugging, will be removed in production
            echo "$i" "`$i getnumber`" "`date +%s`" >> outputs.log
        fi
    done
done < outputs.log

这是一个相当的灾难,最终,它什么也没做,当我碰到它。

Attempt number #2

这一次,我尝试另一种方法的for loop外筑巢while loop

#!/bin/bash

commands=`find /usr/local/bin/ -name 'command*'`
date=`date +%s`


for i in $commands; do
    echo "${i}" "`$i getnumber`"
    name=${i}
    number=`$i getnumber`
    unixtime=$date
    echo "$name" "$number" "$unixtime" # just for debugging, will be removed in production
    while read -r command number unixtime; do
        if ! [ -z ${name+x} ]; then
            echo "$name" "$number" "$unix" >> outputs.log
        else
            if [[ $name = $i ]]; then
                if (( ($date-$unixtime)/60000 > 60 )); then
                    if (( $number >= $current_number_count )); then
                        echo "There isn't a change within the last hour, this is a problem!" # just for debugging, will be removed in production
                        echo -e "$i" "`$i getnumber`" "/" "$number" "\e[31m< No change within last hour."
                    else
                        echo "$i" "`$i getnumber`"
                        echo "There's a change within the last hour, we're good." # just for debugging, will be removed in production
                        # find the line number of $i so we can change it with the new output
                        line_number=`grep -Fn '$i' outputs.log`
                        new_output=`$i getnumber`
                        sed -i "$line_numbers/.*/$new_output/" outputs.log
                    fi
                else
                    echo "$i" "`$i getnumber`"
                    # find the line number of $i so we can change it with the new output
                    line_number=`grep -Fn '$i' outputs.log`
                    output_check="$i getnumber; date +%s"
                    new_output=`eval ${output_check}`
                    sed -i "$line_numbers/.*/$new_output/" outputs.log
                fi
            else
                echo "$i does not exists in the file, adding it now" # just for debugging, will be removed in production
                echo "$i" "`$i getnumber`" "`date +%s`" >> outputs.log
            fi
        fi
    done < outputs.log
done

不幸的是,没有运气对我来说,再次。

有人可以给我伸出援助之手?

Additional notes #2

所以基本上,你运行该脚本第一次,outputs.log是空的,所以你写命令的输出到outputs.log

它已经经过10分钟,再次运行脚本,因为它只有10分钟过去了,而不是一个多小时,该脚本将不检查号码已改变或没有。它不会处理存储的值也显示我们命令的输出,在每个你运行它。 (它们的存在的输出,而不是从存储的值)

在这种10分钟时间表,例如,有可能是添加了新的命令,所以它会检查命令的输出进行存储每次运行脚本的时候,只是为了应对新的命令。

现在,它已经,比方说通过1.2小时,你决定再次运行该脚本,这一次脚本将检查人数还没有一个多小时后,改变和报告我们说Hey! It's been more than an hour passed and those numbers still haven't changed, there might be problem!

Simple explanation

  • 你有100个命令来运行,你的脚本将遍历他们每个人做每一以下;
  • 运行时,你想要的脚本
  • 在每次运行,检查是否outputs.log包含命令 如果outputs.log包含每个循环的命令,检查每个人的最后保存的日期($ unixtime)。 如果最后保存的日期是一个多小时,检查当前的运行和存储的值之间的数字 如果数字还没有超过一个小时的变化,请在红色文本颜色的命令。 如果号码已改变,运行命令和往常一样没有任何警告。 如果最后保存的日期是不到一个小时,运行命令如常。 如果outputs.log不包含命令,简单地将它们存储在文件中,因此它可以被用于下次运行进行检查。
arrays bash for-loop while-loop
1个回答
0
投票

下面使用SQLite数据库来存储,而不是一个平面文件,这使得查询以前运行的历史容易的结果,:

#!/bin/sh

database=tracker.db

if [ ! -e "$database" ]; then
    sqlite3 -batch "$database" <<EOF
CREATE TABLE IF NOT EXISTS outputs(command TEXT
                                 , output INTEGER
                                 , ts INTEGER NOT NULL DEFAULT (strftime('%s', 'now')));
CREATE INDEX IF NOT EXISTS outputs_idx ON outputs(command, ts);
EOF
fi

for cmd in /usr/local/bin/command*; do
    f=$(basename "$cmd")
    o=$("$cmd")
    echo "$f $o"
    sqlite3 -batch "$database" <<EOF
INSERT INTO outputs(command, output) VALUES ('$f', $o);
SELECT command || ' has unchanged output!'
FROM outputs
WHERE command = '$f' AND ts >= strftime('%s', 'now', '-1 hour')
GROUP BY command
HAVING count(DISTINCT output) = 1 AND count(*) > 1;
EOF
done

它列出了不得不每次运行在过去一小时命令产生相同的输出(并跳过那些只运行一次命令)。相反,如果你感兴趣的情况下,最近的每个命令的输出是一样那一小时的时间内完成以前的运行,替换循环与sqlite3的调用:

sqlite3 -batch $database <<EOF
INSERT INTO outputs(command, output) VALUES ('$f', $o);
WITH prevs AS
 (SELECT command
       , output
       , row_number() OVER w AS rn
       , lead(output, 1) OVER w AS prev
  FROM outputs
  WHERE command = '$f' AND ts >= strftime('%s', 'now', '-1 hour')
  WINDOW w AS (ORDER BY ts DESC))
SELECT command || ' has unchanged output!'
FROM prevs
WHERE output = prev AND rn = 1;
EOF

(这需要从释放3.25或更高,因为它使用的功能随后介绍的sqlite3壳)。

© www.soinside.com 2019 - 2024. All rights reserved.