table.txt
次のように誤って作成され、結果に重複しているように見えるいくつかのテーブル()があります。
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1972 1 1 549
1972 1 2 746
...
代わりに、私は以下が欲しい:
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1972 1 1 549
1972 1 2 746
...
だから問題は、結果が表に2回表示されることです。これは、(提供された例を使用して)「1971」の後に再び「1971」ではなく「1972」年を予想する必要があることを意味します。 sh / bashを使用して重複した結果を削除する方法はありますか?
私のデータは1971年から2099年までで、2000年以降も以下の形式とまったく同じ形式であることに注意してください。
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
2000 1 1 875
2000 1 2 456
...
2099 12 31 321
答え1
以下は、相互に排他的な2つのsed
ループです。
sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn' <<""
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1972 1 1 549
1972 1 2 746
...
1972 12 31 999
1972 1 1 933
1972 1 2 837
...
1972 12 31 343
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1972 1 1 549
1972 1 2 746
...
1972 12 31 999
デフォルトでは、rintとrintsed
の2つの状態があります。p
食べる。最初の状態(p
リント状態)では、各入力行をsed
自動的にp
リントし、パターンと比較して確認します/ 12 * 31 /
。現在のパターンスペースが!
一致しない場合はd
削除され、sed
次の入力行が引き出され、 elete コマンドの後に何もp
実行せず、rint コマンドでスクリプトが一番上から再起動されます。d
入力ラインがあるときする/ 12 * 31 /
しかし、試合はsed
台本の後半に入ります -食べるリングの形。最初に:
という分岐ラベルを定義しn
、現在のパターン空間を外部入力ラインで上書きし、現在のn
パターン空間を//
最後の一致パターンと比較します。以前に一致した行がextによって上書きされたため、n
この最初の繰り返しは食べるループが一致せず、毎回ラベルに逆!
追跡されないため、外部入力ラインを取得して最後の一致パターンと再比較します。sed
b
:n
n
//
最後に、別の一致(後で約365行)を作成するn
と、スクリプトが完了したときに自動的に印刷せずに次の入力行を取得し、最初のsed
状態の開始のrintコマンドで-n
一番上から再起動します。p
したがって、各ループ状態は、次のキーをできるだけ少なく見つけながら、同じキーの次の状態にジャンプします。
単一の編集ルーチンを呼び出すことなくスクリプト全体を完了でき、単一の正規表現のみをコンパイルできます。結果として生じる自動装置は非常に簡単です。言い換えれば、[123 ]
とだけ理解します[^123 ]
。さらに、比較の少なくとも半分はコンパイルなしで実行されます。食べるループは単に//
空のループです。したがって、sed
入力行ごとに1回の呼び出しでループを完全に完了できます。regexec()
sed
可能p
リントループと同様の操作を行います。
タイミング
ここにあるさまざまな答えがどのように実行されるのか疑問に思い、自分だけのテーブルを思いつきました。
dash <<""
d=0 D=31 IFS=: set 1970 1
while case "$*:${d#$D}" in (*[!:]) ;;
($(($1^($1%4)|(d=0))):1:)
D=29 set $1 2;;
(*:1:) D=28 set $1 2;;
(*[3580]:)
D=30 set $1 $(($2+1));;
(*:) D=31 set $(($1+!(t<730||(t=0)))) $(($2%12+1))
esac
do printf '%-6d%-4d%-4d%d\n' "$@" $((d+=1)) $((t+=1))
done| head -n1000054 >/tmp/dates
dash <<<'' 6.62s user 6.95s system 166% cpu 8.156 total
これにより、100万以上の行が入力され、/tmp/dates
1970年から3338年まで、毎年出力が2倍になります。ファイルは次のようになります。
tail -n1465 </tmp/dates | head; echo; tail </tmp/dates
3336 12 27 728
3336 12 28 729
3336 12 29 730
3336 12 30 731
3336 12 31 732
3337 1 1 1
3337 1 2 2
3337 1 3 3
3337 1 4 4
3337 1 5 5
3338 12 22 721
3338 12 23 722
3338 12 24 723
3338 12 25 724
3338 12 26 725
3338 12 27 726
3338 12 28 727
3338 12 29 728
3338 12 30 729
3338 12 31 730
...とにかく、いくつかあります。
それから別のコマンドを試しました。
for cmd in "sort -uVk1,3" \
"sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn'" \
"awk '"'{u=$1 $2 $3 $4;if (!a[u]++) print;}'\'
do eval "time ($cmd|wc -l)" </tmp/dates
done
500027
( sort -uVk1,3 | wc -l; ) \
1.85s user 0.11s system 280% cpu 0.698 total
500027
( sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn' | wc -l; ) \
0.64s user 0.09s system 110% cpu 0.659 total
500027
( awk '{u=$1 $2 $3 $4;if (!a[u]++) print;}' | wc -l; ) \
1.46s user 0.15s system 104% cpu 1.536 total
sort
そして、両方のコマンドはsed
半分以内の時間内に完了しましたawk
。これらの結果は一般的です。私はそれらを何度も実行しました。すべてのコマンドが正しい行数を作成しているようです。したがって、おそらくすべてが機能します。
sort
各実行の完了時間はかなり良いですが(通常は少し前進します)、sed
結果を得るには他の2つのコマンドよりも実際の作業が必要です。タスクを完了するために並列タスクを実行しており、マルチコアCPUの利点を大きく享受しています。そして、処理中に割り当てられた単一のコアに固定されたままになります。sed
sort
awk
sed
ここの結果は標準の最新のGNUバージョンから得られたものですが、sed
別のバージョンを試してみました。実際、他のバイナリで3つのコマンドをすべて試しましたが、sed
実際にはこのコマンドだけがガボツールで動作しました。私は他の人が非標準構文のために作業を始める前にエラーで終了したと思います。
可能な限り標準構文を使用することをお勧めします。ほとんどの場合、よりシンプルで完全で効率的な実装を自由に使用できます。
PATH=/usr/heirloom/bin/posix2001:$PATH; time ...
500027
( sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn' | wc -l; ) \
0.31s user 0.12s system 136% cpu 0.318 total
答え2
awkでパイピングしてみてください
awk '!a[$0]++' files.txt > new_files.txt
mv new_files.txt files.txt
これにより、行が一度だけ出力されます。
編集:(varを接続しても問題が解決するかどうかわからない)
awk '{u=$1 $2 $3 $4 ; if ( !a[u]++ ) print ; } ' ...
答え3
$ (head -1 table.txt ; tail -n +2 table.txt | sort -u -V -k1,3)
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
1971 2 1 587
1971 12 31 685
1972 1 1 549
1972 1 2 746
2000 1 1 875
2000 1 2 456
2099 12 31 321