改行で区切られた整数ファイルの場合は、連続した整数を検索してから、壊れていない各シーケンスの連続した整数の数と、各シーケンスが進む方向(昇順または降順)をリストしたいと思います。
私のファイルは次のとおりです。
2
3
4
5
1
7
4
5
6
3
2
1
私が望む出力は次のとおりです。
4^
3^
3v
最初の文字は連続した数字を表し、2番目の文字は数字が昇順か降順かを示します。 Bashでこれを行う方法はありますか?
答え1
Bashではなくawkで。ほとんどの人はbash / shellスクリプトの公正なゲームを検討しています。多くの人。少なくともそれが私にとってうまくいく方法です。
func printrun() {
if(run > 1) {
print run""dir
}
}
NR == 1 {
#print $1" first"
prev = $1
dir = "-"
run = 1
next
}
$1 == prev+1 && dir == "v" {
#print $1" up from down"
printrun()
prev = $1
dir = "^"
run = 2
next
}
$1 == prev+1 {
#print $1" up"
prev = $1
dir = "^"
run++
next
}
$1 == prev-1 && dir == "^" {
#print $1" down from up"
printrun()
prev = $1
dir = "v"
run = 2
next
}
$1 == prev-1 {
#print $1" down"
prev = $1
dir = "v"
run++
next
}
{
#print $1" else"
printrun()
prev = $1
dir = "-"
run = 1
}
END {
#print "end"
printrun()
}
私はコードを圧縮するためにifとelse ifチェーンのバリエーションを試しましたが、このバリエーションが最も明確で読みやすいことがわかりました。
別名で保存run.awk
こうして走る
$ awk -f run.awk inputfile
またはパイプ入力
$ commandproducinginput | awk -f run.awk
説明する:
awkはおおよそ次のように動作します。入力を1行ずつ読みます。各行に対して条件が真のコードブロックを実行します。
コードブロックは中かっこ内にあります。条件はコードブロックの前半です。
condition { code block }
BEGIN
そして、END
最初の行の前と最後の行の後にそれぞれ真の特殊条件です。このコードにはBEGIN
.onlyはありませんEND
。
func
条件ではありません。代わりに、後で使用される関数宣言です。
最初のブロックの条件はですNR == 1
。NR
実際に行番号を意味するレコード番号です。実際、これはブロックが最初の行で実行され、再び実行されないことを意味します。このブロックでは、変数を標準値に初期化します。
このブロックと他のほとんどのブロックはnext
このステートメントで終わります。next
awkにこのループを放棄し、次の行をロードして実行するブロックを見つけるために次のループを開始するように指示します。それを所定の位置に置くと、next
チェーンがあれば効果的に大きな効果を得ることができます。
次のブロックの条件はです$1 == prev+1 && dir == "v"
。これは、現在の数字が前の数字よりも大きいかどうか、移動方向が現在下向きであるかどうかをテストします。両方が真の場合は、進行中のダウンストリーム実行を印刷し、変数を更新して新しいアップリンク実行を開始します。そうでない場合、ブロックは実行されず、awk は実行する次のブロックを探します。
以下の条件とブロックは同様です。
2番目のブロック(END
このブロックの前のブロック)は無条件ブロックです。これは、各行に対して実行されることを意味します。前のブロックのステートメントのために前のブロックがnext
実行されなかった場合にのみ、ブロックが実行されます。実際、このブロックはif else ifチェーンの「else」です。
数値が連続した上または下ではない場合、このブロックに到達します。したがって、このブロックのコードは実行終了に対応する変数を設定します。
擬似コードでは、コードは次のようになります。
if first line:
init vars and set run to none
else if now going up but was going down:
print ongoing run down and start a run up
else if now going up:
start or continue run up
else if now going down but was going up:
print ongoing run up and start a run down
else if now going down:
start or continue run down
else:
print ongoing run and set run to none
if end of input:
print ongoing run
答え2
awk 'function prnt(Xdir){ if (c)print c+1, Xdir; c=0 }
(pre+1==$0){ prev_dir=dir; dir="▲"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=$0; next }
(pre==$0+1){ prev_dir=dir; dir="▼"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=$0; next }
c{ prnt(dir) }
{ pre= $0}
END{ prnt(dir) }' infile
4 ▲
3 ▲
3 ▼