1つのディレクトリにある多くの* .txtファイルを処理したいと思います。共通構造(区切られた共通ヘッダー)があります。しかし、1行あたりの行数はさまざまで、一部は1行、一部は8行に達します。
各ファイルの最初の行と最後の行を除くすべての行を削除したいと思います。役に立つアドバイスはありますか?
修正する:要求に応じていくつかのテストデータファイルを提供しました。
stat87.txt
Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;
87; ; 46.1123; 8.5440;19010101;19661229;Dres
stat01.txt
Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;
1; ; 47.8400; 8.8500;18910101;19580228;Aach
1; 478; 47.8413; 8.8493;19580301;19860630;Aach
たとえば、stat56.txt です。
Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;
56; ; 46.4580; 7.6320;18980101;19450321;Hamb
56; ; 46.4580; 7.6320;19450321;19880511;Hamb
56; 103; 46.4411; 7.6345;19880601;19990630;Hamb
この場合、ステーションの時間範囲をキャプチャするために、特に列5の最初の行と列6の最後の行を維持したいと思います。
結果:
find . -type f -name \*.txt -printf "%f\0" | xargs -0 -I xxxx sed -ni '
2 {
$ {
s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\);\([^;]*\).*$/\1;\2/
p
q
}
s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$/\1/
p
}
$ {
s/^[^;]*;[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$/\1/
p
}' xxxx
生産する....
19010101;19661229
18910101
19860630
18980101
19990630
次に、単純なsedループを使用して;を追加して最終ファイルをクリーンアップしました。
'for file in *.txt; do
sed 'N;s/\n/;/' "$file" > "cleaned$file"
done'
19010101;19661229
18910101;19860630
18980101;19990630
答え1
完璧です。 awkのバージョンは次のとおりです。
find . -type f -name \*.txt -printf "%f\0" | xargs -0 -I xxxx sed -ni '
2 {
$ {
s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\);\([^;]*\).*$/\1;\2/
p
q
}
s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$/\1/
h
}
$ {
s/^[^;]*;[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$/\1/
H
x
s/\n/;/
p
}' xxxx
本当に有名な方ありがとうございますSed - Bruce Barnettの紹介とチュートリアル
結果:
$ cat stat01.txt
18910101;19860630
$ cat stat56.txt
18980101;19990630
$ cat stat87.txt
19010101;19661229
----
参考のための最初のバージョン
あなたの意見に基づいて、データファイル形式とそれを処理するsedスクリプトを開発しました。
試してみてください:
$ find . -type f -name \*.txt -printf "%f\0" | xargs -0 -I xxxx sed -ni '
2 {
$ {
s/^[^;]*;\([^;]*\);\([^;]*\).*$/\1;\2/
p
q
}
s/^[^;]*;\([^;]*\).*$/\1/
p
}
$ {
s/^[^;]*;[^;]*;\([^;]*\).*$/\1/
p
}' xxxx
ヘッダーを含む最初の行を削除します。
見つかった最初のデータラインの列2とファイルの最後のデータラインの列3のみを保持します。
ファイルにデータ行が 1 つしか含まれていない場合、列 2 と 3 は 1 行に残ります。
ハハ、変だったけど本当に楽しかったです!
現在のディレクトリのデータファイル:
$ cat test01.txt
Name;Price;Amount;Description
Bread;2.1;3;healthy one
$ cat test02.txt
Name;Price;Amount;Description
Water;0.0;100;For life
Wine;10.3;1;Less than half a glass a day
$ cat test03.txt
Name;Price;Amount;Description
House;1000.0;1;home
Car;500.5;0;no need
Bike;10.3;5;Good for the planet and for me
結果:
$ cat test01.txt
2.1;3
$ cat test02.txt
0.0
1
$ cat test03.txt
1000.0
5
2つの簡単なデータファイルの内容と期待される結果を提供していただければ、この回答を修正いたします。
答え2
これを行うには、ファイルを繰り返す必要があります。
for file in *.txt; do
lines=$(wc -l < "$file")
if [ "$lines" -lt 3 ]; then
echo "$file is short enough, not touching it."
else
# for testing, you can also use the -i option
sed -n '1p;$p' "$file" > "$file.new"
fi
done
ファイルの長さが1行だけの場合はループが必要です。とともにthrig のコマンド2回表示されます(試してみてくださいecho 1|sed -n '1p;$p'
)。
答え3
これはGawkがsedよりも優れたツールです。元のメソッドの find-xargs パイプラインを再利用し、同じ出力命名法を使用します。
find . -type f -name \*.txt -printf "%f\0" | xargs -0 gawk -F\; '
FNR==2 { von = $5 }
ENDFILE { print von FS $6 > "cleaned" FILENAME }
'
コードがより簡単になり、明確になり、メンテナンスが簡単になります。