使用时间戳bash删除超过一小时的文件中的行

时间:2015-10-17 11:05:45

标签: bash sed timestamp

有点麻烦试图让以下工作。

我有一个包含hostname:timestamp的文件,如下所示:

hostname1:1445072150
hostname2:1445076364

我正在尝试创建一个bash脚本来查询此文件(使用cron作业)来检查时间戳是否超过1小时,如果是,请删除该行。 下面是我到目前为止,但它似乎没有删除文件中的行。

#!/bin/bash

hosts=/tmp/hosts
current_timestamp=$(date +%s)

while read line; do
    hostname=`echo $line | sed -e 's/:.*//g'`
    timestamp=`echo $line | cut -d ":" -f 2`
    diff=$(($current_timestamp-$timestamp))
    if [ $diff -ge 3600 ]; then
            echo "$hostname - Timestamp over an hour old. Deleting line."
            sed -i '/$hostname/d' $hosts
    fi
done <$hosts

我设法让时间戳部分正确地识别超过一小时但仍无法从文件中删除时间的主机。

我怀疑这可能是由于while循环保持文件打开但不是100%确定如何解决它。还尝试制作文件的副本并编辑但仍然没有。

替代方案:如果有更好的方法让这个工作并产生相同的结果,我愿意接受建议:)

非常感谢任何帮助。

干杯

2 个答案:

答案 0 :(得分:2)

脚本中的问题只是这一行:

sed -i '/$hostname/d' $hosts

单引号内的变量未扩展为其值, 所以该命令试图用字面意思替换&#34; $ hostname&#34;,而不是它的值。如果用双引号替换单引号, 变量将扩展到它的值,这就是你需要的:

sed -i "/$hostname/d" $hosts

可以进行改进:

#!/bin/bash

hosts=/tmp/hosts
current_timestamp=$(date +%s)

while read line; do
    set -- ${line/:/ }
    hostname=$1
    timestamp=$2
    ((diff = current_timestamp - timestamp))
    if ((diff >= 3600)); then
        echo "$hostname - Timestamp over an hour old. Deleting line."
        sed -i "/^$hostname:/d" $hosts
    fi
done <$hosts

改进:

  • sed命令中更严格的模式,使其更强大并避免一些潜在的错误
  • 提取主机名部分和时间戳部分而不使用任何子shell的简单方法
  • 通过封闭在((...))
  • 内的简单算术运算

答案 1 :(得分:1)

您要求替代方案 - 使用awk

awk -F: -v ts=$(date +%s) '$2 <= ts-3600 { next }' $hosts > $hosts.$$
mv $hosts.$$ $hosts

ts=$(date +%s)awk变量ts设置为date的值。该脚本会跳过第二列(第一个冒号后)中的值小于阈值的所有行。如果你愿意,可以在BEGIN块中进行一次减法。确定<=<是否适用于您的目的。

如果您需要知道哪些行已删除,可以添加

printf "Deleting %s - timestamp %d older than %d\n", $1, $2, (ts-3600) >/dev/stderr;

next之前打印标准错误信息。如果必须将其写入标准输出,则需要安排将保留行写入具有print > file的文件作为过滤条件之后的替代操作(将-v file="$hosts.$$"作为另一对参数传递给awk)。可以做出的调整是无止境的。

如果文件的大小很大,将文件的相关子部分一次复制到临时文件然后复制到最终文件比在原始代码中多次编辑文件更快。如果文件足够小,则没有问题。