ファイルから特定のマルチパターンのみを抽出する

ファイルから特定のマルチパターンのみを抽出する

次のファイルがあります。

 $less dummyKeyAndValue.txt
   apiKey=key1;some_other_data;term=abc
   apiKey=key2;some_other_data;some_other_data;term=def
   term=pqr;some_other_data;apiKey=key1
   apiKey=key3;some_other_data;term=def

私が望む出力は次のとおりです。

 $less dummyNewFile.txt
   apiKey=key1 term=abc
   apiKey=key2 term=def
   apiKey=key1 term=pqr
   apiKey=key3 term=def

主に dummyKeyAndValue.txt ファイルから「apiKey」と「term」を抽出しようとします。どちらもファイル内で異なる順序で表示されることがあります。次のコマンドを試しました。

   $cat dummyKeyAndValue.txt | tee >(egrep -o 'apiKey=[a-zA-Z0-9]+')  |   
   egrep -o 'term=[a-zA-Z]+' | less

私が得た結果は次のとおりです。

     term=abc
     term=def
     term=pqr
     term=def

希望の出力を得るためにコマンドを使用するのに役立つ人はいますか?

答え1

このawkベースのソリューションは、読みやすさとメンテナンスが簡単なため、役に立ちます。 awkは、テキストファイル内の列などの値を解析するために選択するツールであることがよくあります。

/tmp$ cat a.awk
{
   keypart=substr($0, index($0, "apiKey=")+7)
   keyvalue=substr(keypart, 1, index(keypart, ";")-1)

   termpart=substr($0, index($0, "term=")+5)
   termvalue=substr(termpart, 1, index(termpart, ";")-1)

# If the attribute is last on the input line there will be no ; to mark the end so use the whole part
   if(keyvalue=="") {keyvalue=keypart}
   if(termvalue=="") {termvalue=termpart}
   printf ("  apikey=%s term=%s\n", keyvalue, termvalue)
}

Awkスクリプト(上記ではa.awkという名前の意味のあるファイル名を使用できます)は、次のように使用できます。

awk -f a.awk inputfile

ご覧のとおり、各フィールドの if ステートメントを使用して、行末で終わる入力フィールドの場合を処理しました。この状況を自動的に処理するには、このスクリプトを次のように改善します。

/tmp$ cat a.awk  
{
   LINE=$0 ";"

   keypart=substr(LINE, index(LINE, "apiKey=")+7)
   keyvalue=substr(keypart, 1, index(keypart, ";")-1)

   termpart=substr(LINE, index(LINE, "term=")+5)
   termvalue=substr(termpart, 1, index(termpart, ";")-1)

   printf ("  apikey=%s term=%s\n", keyvalue, termvalue)
}

より多くのケースを追加するほど、利点はより明確になります!

答え2

代わりに、非常に効果的ですが少し複雑なソリューション

sed 'G;s/;/\n/' | awk -F= '
$1~/apiKey/ {key=$2}
$1~/term/ {term=$2}
/^$/ {printf("  apiKey=%s term=%s\n", key, term)
      key=""
      term=""}'

まず、sedは2つのタスクを実行するために使用されます。 「G」コマンドは各「レコードセット」の後に開いた行を効果的に追加し、2番目に「replace」コマンド(s/;/\n/)は各レコードセットを1行につき1つのオープン行に効果的に拡張します;。各キャラクター。 sedが生成するものは1行に1つのキーと値のペアであり、各レコードの終わりを指定する空行があります。

その後、awkは興味のある属性を見つけるために最初のフィールドだけを見て、値を見つけるために2番目のフィールドを見るだけで、indexやsubstrは必要ありません。 awkが「空行」に遭遇すると、見つかった値を印刷します。機能を復元するには、各レコードの末尾の値を「消去」するだけです。 -シンボルに基づいて行をフィールドに分割するように-F=awkに指示するには、-を使用します。=

$1 ~ /.../「最初のフィールドが値と一致する場合」を意味します。/.../

次に、変数(キーまたは用語)に値を割り当てます。

/^$/「awkが空行に出会ったとき」を意味します。

答え3

非常に効率的ではないかもしれませんが、「two grep」アプローチを追求したい場合は、以下を使用できますpaste

$ paste <(grep -o 'apiKey=[^;]*' dummyKeyAndValue.txt) <(grep -o 'term=[^;]*' dummyKeyAndValue.txt)
apiKey=key1     term=abc
apiKey=key2     term=def
apiKey=key1     term=pqr
apiKey=key3     term=def

または、GNUのKISSメソッドを使用してくださいsed

sed -nE -e 's/(apiKey=[^;]*).*(term=[^;]*)/\1 \2/p' \
  -e 's/(term=[^;]*).*(apiKey=[^;]*)/\2 \1/p' dummyKeyAndValue.txt

関連情報