2015-10-17 103 views
2

试图让以下工作有点麻烦。使用时间戳bash删除超过一个小时的文件中的行

我有如下含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

改变封闭于'DIFF = $提取的主机名部分和时间戳部分而没有任何副壳

  • 简单的算术运算((CURRENT_TIMESTAMP时间戳))'和sed的需要报价扩展: 'sed -i“/ $ hostname/d”$ hosts' – amdixon

  • +0

    Cheers @amdixon。这似乎已经成功了。非常感谢:) – Kev

    +2

    不用担心,代码几乎已经工作 – amdixon

    回答

    2

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

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

    单引号内的变量没有扩展到他们的价值观, 所以命令试图取代字面意思是“$主机名”,而不是其值。如果换成单引号用双引号, 变量将得到扩展到它的价值,这是你所需要的是什么:

    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命令

    • 更严格的模式,以使其更加坚固并避免一些潜在的错误
    • 小号impler方式通过内((...))
    +0

    amdixon帮助我们找到脚本的问题,但感谢改进,尤其是解释每个人(Y) – Kev

    1

    你问到我的选择 - 使用awk

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

    ts=$(date +%s)设置awk变量tsdate值。脚本将跳过第二列(第一个冒号后面)的值小于阈值的任何行。如果您愿意,您可以在BEGIN块中进行一次减法。确定<=<对于您的目的是否正确。

    如果您需要知道哪些行被删除,可以在next前加

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

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

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

    相关问题