显示文件连续行之间的更改

显示文件连续行之间的更改

有没有一种简单的方法可以查看文件中行的变化情况?例如,假设我有这个“my.log”文件:

cpu1 cpu2 cpu3 cpu4
   5    3    3    6
   5    3    3    6
   5    0    3    6
   3    0    6    6
   5    3    3    0

从命令行,我想输入类似“cat my.log | showchanges”的内容,然后看到类似这样的内容:

cpu1 cpu2 cpu3 cpu4
   5    3    3    6
   "    "    "    "
   "    0    "    "
   3    "    6    "
   5    3    3    0

理想情况下,“showchanges”会贪婪地将任何一段空白视为列分隔符来执行此操作,但我对细节非常灵活。我只是想在有很多列时轻松看到变化。另外,最终最好省略根本没有变化的行。

答案1

awk '{ bak=$0; for(i=1; i<=NF; i++)$i=($i==tmp[i]?"-":$i)
       split(bak, tmp)
}1' infile

cpu1 cpu2 cpu3 cpu4
5 3 3 6
- - - -
- 0 - -
3 - 6 -
5 3 3 0

要保持记录缩进(字段宽度为 4):

awk '{ bak=$0; for(i=1; i<=NF; i++)$i=sprintf("%4s", ($i==tmp[i]?"-":$i))
       split(bak, tmp)
}1' infile

cpu1 cpu2 cpu3 cpu4
   5    3    3    6
   -    -    -    -
   -    0    -    -
   3    -    6    -
   5    3    3    0

答案2

确实如此:这不是代码编写服务。但如果一项任务很简单或有趣,我们中的一些人就会采取行动。 (-;

假设你不会编写程序,你仍然可以使用sed, no real one-liner 具有这样的行长度:

sed -E -e '1h;1n;H;x;s/$|\n/_&/g;:1' -e 's/( +)([^ ]+)_(.*)\1\2_/_\1\2\3_\1"/;t1' -e '/^_/!s/( +[^ ]+)_/_\1/g;/^_/!b1' -e 's/.*_//'

我确实在第一行的开头添加了一个空格,以使文件保持一致(其他行也以空格开头)。这个想法是将旧行保留在旧空间中并处理一对行,使用下划线(如果下划线可以是文件的一部分,则使用不同的标记)作为检查相同记录的标记。

注意:恐怕这并不是真正的标准,因为扩展正则表达式中没有定义反向引用,但是用基本正则表达式编写它看起来真的很混乱。无论如何,我不知道有哪个sed版本不支持 ERE 中的反向引用。

让我们把它写得更易读:

sed -E '1h;1n;# handle the first line
  H;x;# add current line to hold space and exchange buffers to store the current line
  s/$|\n/_&/g;# now add the underscore add the end of the lines
  :1
  s/( +)([^ ]+)_(.*)\1\2_/_\1\2\3_\1"/;# if the record at the _ is repeated in the new line, replace it with a quote, advance the _ and repeat
  t1
  /^_/!s/( +[^ ]+)_/_\1/g;# the t did not loop, so if we are not the done, advance the _ and process if necessary
  /^_/!b1
  s/.*_//;# finally remove everything before the processed line'

答案3

watch -d tail my.log
(default parameters, equivalent to : watch -d -n 2 tail -n 10 my.log)

watch -d -n 5 tail -n 15 my.log
At 5 seconds interval, watch last 15 lines from my.log

man watch
   -d, --differences [permanent]
          Highlight  the differences between successive updates.  
          Option will read optional argument that changes highlight to be permanent, 
          allowing to see what has changed at least once since first iteration.

   -n, --interval seconds
          Specify  update interval.  
          The command will not allow quicker than 0.1 second interval,
          in which the smaller values are converted. 
          Both '.' and ',' work for any locales.

man tail
   -n, --lines=[+]NUM
          output the last NUM lines, instead of the last 10; 
          or use -n +NUM to output starting with line NUM

答案4

将您的示例与 bash 脚本一起使用。我将其命名为 myscript.sh

#!/bin/bash
FILENAME=$1
LINEAS=$(cat "$FILENAME" | wc -l)
N=1
while read LINE
do
if [[ $N -gt 1 ]]; then
    if [[ $N -eq 2 ]]; then
        echo $LINE
        PREVIA=$LINE
    else
        L1=$(echo "$LINE" |awk -F' ' '{print $1}')
        L2=$(echo "$LINE" |awk -F' ' '{print $2}')
        L3=$(echo "$LINE" |awk -F' ' '{print $3}')
        L4=$(echo "$LINE" |awk -F' ' '{print $4}')
        P1=$(echo "$PREVIA" |awk -F' ' '{print $1}')
        P2=$(echo "$PREVIA" |awk -F' ' '{print $2}')
        P3=$(echo "$PREVIA" |awk -F' ' '{print $3}')
        P4=$(echo "$PREVIA" |awk -F' ' '{print $4}')
        if [[ $L1 -eq $P1 ]]; then
            R1="-"
        else
            R1="$L1"
        fi
        if [[ $L2 -eq $P2 ]]; then
            R2="-"
        else
            R2="$L2"
        fi
        if [[ $L3 -eq $P3 ]]; then
            R3="-"
        else
            R3="$L3"
        fi
        if [[ $L4 -eq $P4 ]]; then
            R4="-"
        else
            R4="$L4"
        fi
        echo $R1" "$R2" "$R3" "$R4
        PREVIA=$LINE
    fi
fi
let "N=N+1"
done < $FILENAME

执行脚本

./myscript.sh my.log

结果是:

5 3 3 6
- - - -
- 0 - -
3 - 6 -

相关内容