2017-11-13 2 views
1

Angenommen, eine mehrzeilige Textdatei (file1) enthält ein Schlüsselwort pro Zeile, wobei jedes Schlüsselwort das Format String Integer hat. Die Reihenfolge der Zeilen ist festgelegt.Schlüsselwortsuche mit ganzen Zahlen ohne führende Nullen mit sed und awk

$cat file1 
foo1 
foo2 
foo4 
foo10 

Nehmen wir weiter an einem mehrzeiligen Textdatei (file2), dessen Linien mehrere Leerzeichen getrennte Wörter enthalten, von denen eine der oben genannten Schlüsselwörter sein kann. Jede Zeile kann nur ein Schlüsselwort enthalten, und das Schlüsselwort darf sich irgendwo in der Zeile befinden, außer als letztes Wort. Wenn ein Schlüsselwort in der Zeile existiert, dann existiert der Begriff baz=() auch in der Zeile. Die Reihenfolge der Zeilen ist nicht festgelegt.

$cat file2 
foo1 bar baz=() 
bar foo4 baz=() 
foo10 qux baz=() 
foo2 baz=() 

Wenn eine Zeile in file2 Schlüsselwort n enthält, möchte ich die Zeilennummer hinzuzufügen, das Schlüsselwort n in file1 im baz=() Begriff hat.

$sought_commands file1 file2 
foo1 bar baz=(1) 
bar foo4 baz=(3) 
foo10 qux baz=(4) 
foo2 baz=(2) 

kam ich mit dem folgenden Code auf, der den Fehler hat, die foo1 Masken der Begriff baz=() für Stichwort foo10 Stichwort:

for kw in $(cat file1); do 
    lineNumbr=$(cat file1 | awk '/'$kw'/{print NR; exit}') 
    sed -i "/$kw/ s/baz\=()/baz\=($lineNumbr)/" file2 
done 

.

$cat file2 
foo1 bar baz=(1) 
bar foo4 baz=(3) 
foo10 qux baz=(1) # ERROR! 
foo2 baz=(2) 

Edit 1: Ich prüfte den Umstand mit, dass die Schlüsselwörter werden immer von einem Leerzeichen gefolgt in file2 als Trennzeichen, aber dann die awk-Befehl schlägt fehl:

for kw in $(cat file1); do 
    kw_adj="$kw " 
    lineNumbr=$(cat file1 | awk '/'$kw_adj'/{print NR; exit}') 
    sed -i "/$kw_adj/ s/baz\=()/baz\=($lineNumbr)/" file2 
done 

awk: cmd. line:1: /foo1 
awk: cmd. line:1:^unterminated regexp 
awk: cmd. line:1: /foo2 
awk: cmd. line:1:^unterminated regexp 
awk: cmd. line:1: /foo4 
awk: cmd. line:1:^unterminated regexp 
awk: cmd. line:1: /foo10 
awk: cmd. line:1:^unterminated regexp 
+0

wenn Sie Dateiinhalte in bash sind Looping und mit 'awk' (und' sed') du machst wahrscheinlich etwas falsch. – karakfa

Antwort

1

Das Problem ist hier:

sed -i "/$kw/ s/baz\=()/baz\=($lineNumbr)/" file2 

Wenn der Wert von kw ist "foo1", das Muster /$kw/ matches "foo10" als auch, foo10 qux baz=() mit foo10 qux baz=() ersetzen. Sobald dies in die Datei geschrieben wurde, ist baz=() nicht mehr vorhanden. Wenn also das Muster "foo10" von der Eingabe übernommen wird, hat es nichts zu ersetzen.

Änderung, wie diese Zeile:

sed -i "/\<$kw\>/ s/baz\=()/baz\=($lineNumbr)/" file2 

Die \<...\> macht eine Mustererkennung Wortgrenze. Auf diese Weise wird "foo10" nicht von /\<foo1\>/ abgeglichen, nur das komplette Wort "foo1".

Auch die lineNumbr=$(...) innerhalb der Schleife ist albern, , wenn Sie bereits die Zeilennummer mit einfachen Zählen wissen können:

lineNumbr=1 
for kw in $(cat file1); do 
    sed -i "/\<$kw\>/ s/baz\=()/baz\=($lineNumbr)/" file2 
    ((lineNumbr++)) 
done 
+0

Danke für die Erklärung. Ihre Lösung ist auf der Ebene, die ich verstehen kann. –

1

awk auf die Rettung!

$ awk 'NR==FNR {a[$1]=NR; next} 
    /baz=\(\)$/ {for(i=1;i<NF;i++) 
        if($i in a) sub(/\(\)$/,"(" a[$i] ")")}1' file{1,2} 

foo1 bar baz=(1) 
bar foo4 baz=(3) 
foo10 qux baz=(4) 
foo2 baz=(2) 
Verwandte Themen