参加したいファイルが2つあり、それぞれ約12900と4400のエントリがあります。ファイルには、世界中のすべての陸上気象観測所の位置情報が含まれています。最大のファイルは隔週で更新され、小さいファイルは年に1回程度更新されます。元のファイルはここにあります( http://www.wmo.int/pages/prog/www/ois/volume-a/vola-home.htm および http:/ /weather.rap.ucar.edu/surface/stations.txt )。私が持っているファイルは、awk、sed、bashの混合スクリプトを使用してすでに操作されています。私はファイルを使用して、Unidataから無料で入手できるGEMPAKパッケージを使用してデータを視覚化します。最大のファイルはGEMPAKで機能しますが、その全機能では機能しません。このためには結合が必要です。
ファイル1には、気象観測ステーションの位置情報が含まれています。最初の6桁は一意のステーション識別子です。さまざまなパラメータ(駅番号、駅名、国コード、緯度経度、駅の標高)は、ライン内の位置によってのみ定義されます。つまり、タブはありません。
060090 AKRABERG FYR DN 6138 -666 101
060100 VAGA FLOGHAVN DN 6205 -728 88
060110 TORSHAVN DN 6201 -675 55
060120 KIRKJA DN 6231 -631 55
060130 KLAKSVIK HELIPORT DN 6221 -656 75
060160 HORNS REV A DN 5550 786 21
060170 HORNS REV B DN 5558 761 10
060190 SILSTRUP DN 5691 863 0
060210 HANSTHOLM DN 5711 858 0
060220 TYRA OEST DN 5571 480 43
060240 THISTED LUFTHAVN DN 5706 870 8
060290 GROENLANDSHAVNEN DN 5703 1005 0
060300 FLYVESTATION AALBORG DN 5708 985 13
060310 TYLSTRUP DN 5718 995 0
060320 STENHOEJ DN 5736 1033 56
060330 HIRTSHALS DN 5758 995 0
060340 SINDAL FLYVEPLADS DN 5750 1021 28
ファイル2には、ファイル1の一意の識別子と2番目の4文字の識別子(ICAOロケーター)が含まれています。
060100 EKVG
060220 EKGF
060240 EKTS
060300 EKYT
060340 EKSN
060480 EKHS
060540 EKHO
060600 EKKA
060620 EKSV
060660 EKVJ
060700 EKAH
060780 EKAT
2つのファイルを結合して、結果のファイルの行の最初の4つの位置に4文字の識別子が含まれるようにします。つまり、識別子が4つのスペースを置き換える必要があります。
060090 AKRABERG FYR DN 6138 -666 101
EKVG 060100 VAGA FLOGHAVN DN 6205 -728 88
060110 TORSHAVN DN 6201 -675 55
060120 KIRKJA DN 6231 -631 55
060130 KLAKSVIK HELIPORT DN 6221 -656 75
060160 HORNS REV A DN 5550 786 21
060170 HORNS REV B DN 5558 761 10
060190 SILSTRUP DN 5691 863 0
060210 HANSTHOLM DN 5711 858 0
EKGF 060220 TYRA OEST DN 5571 480 43
EKTS 060240 THISTED LUFTHAVN DN 5706 870 8
060290 GROENLANDSHAVNEN DN 5703 1005 0
EKYT 060300 FLYVESTATION AALBORG DN 5708 985 13
060310 TYLSTRUP DN 5718 995 0
060320 STENHOEJ DN 5736 1033 56
060330 HIRTSHALS DN 5758 995 0
EKSN 060340 SINDAL FLYVEPLADS DN 5750 1021 28
Bashやawkスクリプトを使用してこのタスクを実行することは可能ですか?
awk 'BEGIN { while(getline < "file2" ) { codes[$1] = $2 } }
{ printf "%4s%s\n", codes[$1], substr($0, 5) }' file1
私たちのカップルは、join
のみを使用してこの問題を解決できるかどうかを確認したいと考えていました。これは私の試みです。それは部分的に機能するので、@ Terdonは私に夕食を借りています8-)。
$ join -a1 -1 1 -2 1 -o 2.2 1.1 1.2 1.3 1.4 1.5 1.6 1.7 -e "N/A" \
<(sort file1) <(sort file2)
$ join -a1 -1 1 -2 1 -o 2.2 1.1 1.2 1.3 1.4 1.5 1.6 1.7 -e "N/A" <(sort file1) <(sort file2) | column -t
N/A 060090 AKRABERG FYR DN 6138 -666 101
EKVG 060100 VAGA FLOGHAVN DN 6205 -728 88
N/A 060110 TORSHAVN DN 6201 -675 55 N/A
N/A 060120 KIRKJA DN 6231 -631 55 N/A
N/A 060130 KLAKSVIK HELIPORT DN 6221 -656 75
N/A 060160 HORNS REV A DN 5550 786
N/A 060170 HORNS REV B DN 5558 761
N/A 060190 SILSTRUP DN 5691 863 0 N/A
N/A 060210 HANSTHOLM DN 5711 858 0 N/A
EKGF 060220 TYRA OEST DN 5571 480 43
EKTS 060240 THISTED LUFTHAVN DN 5706 870 8
N/A 060290 GROENLANDSHAVNEN DN 5703 1005 0 N/A
EKYT 060300 FLYVESTATION AALBORG DN 5708 985 13
N/A 060310 TYLSTRUP DN 5718 995 0 N/A
N/A 060320 STENHOEJ DN 5736 1033 56 N/A
N/A 060330 HIRTSHALS DN 5758 995 0 N/A
EKSN 060340 SINDAL FLYVEPLADS DN 5750 1021 28
上記は、join
で利用可能なほとんどすべてのオプションを利用しています。これは、ある種のフランケンシュタインの方法のように、間違って使用していることを腸に伝えますが、私たちはすべてここで学習しているので、それで問題ありません...私は推測します。
スイッチ-a1
は、file1のfile2からの対応する一致がない行を含めるようにjoinに指示します。したがって、これがこれらの線を表示するように駆り立てるものです。
N/A 060330 HIRTSHALS DN 5758 995 0 N/A
-1 1
と-2 1
は、主に最初の列である2つのファイルの行を結合する列を示しています。 -o ...
は、2つのファイルのどの列をどの順序で表示するかを示しています。
-e "N/A"
は、join
によって空と見なされるフィールドを出力するためのプレースホルダー値として、文字列「N/A」を使用することを示しています。
最後の2つの引数は、joinコマンドにソートされた2つのファイルfile1
とfile2
をフィードしています。
これは進行中の作業であり、join
コマンドを使用してこのタイプの問題を解決する方法を示しようとしているので、親切にしてください。これは、意図されたタイプの問題のように思われるためです。
3列目
主要なものは、1ワードと2ワードの値が混在しているため、3番目の列とどのように競合するかです。これはjoin
にとって大きな障害のようであり、それを回避する方法がわかりません。任意のガイダンスをいただければ幸いです。
間隔
元の間隔はすべてjoin
で失われ、それを維持する方法もわかりません。したがって、join
は、結局のところ、これらのタイプの問題に対処する正しい方法ではない可能性があります。
でもうまくいくようですか?
コマンドラインで何度も曲げた後、一般的な解決策があり、少なくとも部分的には機能するように見えるので、これを解決策のコアで使用し、awk
やsed
などの他のツールを使用してクリーンアップすることができますそれを上げます。ただし、これは疑問を投げかけます。「awk
&sed
を使用してクリーンアップする場合は、それらを直接使用する方がよいでしょうか?」.
これはshouldjoin
を使用して可能ですが、スペースと空のフィールドを正しく出力する方法がわかりません。とにかく、この小さなPerlスクリプトはトリックを行います:
#!/usr/bin/env Perl
## Open file2, the one that contains the codes
## it is expected to be the 1st argument given to the script.
open($a,"$ARGV[0]");
## Read the number<=>code pairs into a hash (an associative array)
## called 'k'
while (<$a>) {
chomp; @f=split(/\s+/); $k{$f[0]}=$f[1];
}
## Open file1, the one that contains the data
## it is expected to be the 2nd argument given to the script.
open($b,"$ARGV[1]");
## Go through the file
while (<$b>) {
## Split each line at white space into the array @f
@f=split(/\s+/);
## $f[1] is the 6 digit number that defines the different stations.
## If this number has an entry in the hash %k, if it was found
## in file2, replace the first 4 spaces with its value from the hash.
s/^\s{4}/$k{$f[1]}/ if defined($k{$f[1]});
## Print each line of the file
print;
}
これをfoo.pl
として保存し、次のように実行します。
$ Perl foo.pl file2 file1
060090 AKRABERG FYR DN 6138 -666 101
EKVG 060100 VAGA FLOGHAVN DN 6205 -728 88
060110 TORSHAVN DN 6201 -675 55
060120 KIRKJA DN 6231 -631 55
060130 KLAKSVIK HELIPORT DN 6221 -656 75
060160 HORNS REV A DN 5550 786 21
060170 HORNS REV B DN 5558 761 10
060190 SILSTRUP DN 5691 863 0
060210 HANSTHOLM DN 5711 858 0
EKGF 060220 TYRA OEST DN 5571 480 43
EKTS 060240 THISTED LUFTHAVN DN 5706 870 8
060290 GROENLANDSHAVNEN DN 5703 1005 0
EKYT 060300 FLYVESTATION AALBORG DN 5708 985 13
060310 TYLSTRUP DN 5718 995 0
060320 STENHOEJ DN 5736 1033 56
060330 HIRTSHALS DN 5758 995 0
EKSN 060340 SINDAL FLYVEPLADS DN 5750 1021 28
Bashで十分です。
#!/usr/bin/env bash
# ### create a psuedo hash of icao locator id's
# read each line into an array
while read -a line; do
# set icao_nnnnnn variable to the value
declare "icao_${line[0]}"=${line[1]}
done <file2
# ### match up icao id's from file1
# read in file line at a time
while IFS=$'\n' read line; do
# split the line into array
read -a arr <<< "$line"
# if the icao_nnnnnn variable exists, it will print out
var="icao_${arr[0]}"
printf "%-8s %s\n" "${!var}" "$line"
done <file1
「ハッシュ」で何が起こっているかの詳細については、これを参照してください SO回答 Bash 4は連想配列をネイティブにサポートしていますが、これは3 + 4(おそらく2?)で機能するはずです。
書式設定を取得するには、file1から行を左トリミングする必要がある場合があります。
join
(+さらにいくつかのツール)を使用して間隔を維持する簡単な方法を次に示します。両方のファイルはステーション番号でソートされているように見えるため、追加のソートは必要ありません。
_join -j1 -a1 -o 2.2 -e " " file1 file2 | paste -d' ' - <(cut -c6- file1)
_
パイプの前の部分は、slmが 彼の答え で使用したものと非常に似ているので、もう一度説明しません。唯一の違いは、_-e " "
_を使用していることです。これは、欠落している入力フィールドの代わりに4つのスペースの文字列を使用し、_-o 2.2
_を使用してfile2の2番目のフィールドのみを出力します。
したがって、_join -j1 -a1 -o 2.2 -e " " file1 file2
_は4文字幅の列を生成します(下には表示されませんが、EK **の後には何も表示されず、空の行は実際には4つのスペースです):
EKVG EKGF EKTS EKYT EKSN
次に、これを(区切り文字としてスペースを使用して)paste
file1に移動し、そこからcut
最初の5文字| paste -d' ' - <(cut -c6- file1)
最終結果:
_ 060090 AKRABERG FYR DN 6138 -666 101
EKVG 060100 VAGA FLOGHAVN DN 6205 -728 88
060110 TORSHAVN DN 6201 -675 55
060120 KIRKJA DN 6231 -631 55
060130 KLAKSVIK HELIPORT DN 6221 -656 75
060160 HORNS REV A DN 5550 786 21
060170 HORNS REV B DN 5558 761 10
060190 SILSTRUP DN 5691 863 0
060210 HANSTHOLM DN 5711 858 0
EKGF 060220 TYRA OEST DN 5571 480 43
EKTS 060240 THISTED LUFTHAVN DN 5706 870 8
060290 GROENLANDSHAVNEN DN 5703 1005 0
EKYT 060300 FLYVESTATION AALBORG DN 5708 985 13
060310 TYLSTRUP DN 5718 995 0
060320 STENHOEJ DN 5736 1033 56
060330 HIRTSHALS DN 5758 995 0
EKSN 060340 SINDAL FLYVEPLADS DN 5750 1021 28
_