ファイルの行がどのように変更されたかを簡単に確認する方法はありますか?たとえば、次の「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
次の行長を持つ実際の1行コードは使用できません。
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 -