web-dev-qa-db-ja.com

区切り文字の位置に基づいて区切り文字内を置き換えるUNIXコマンド

| [パイプ]区切り文字を含む入力文字列があり、空の文字列の3番目と5番目の列を&文字に置き換えるのが好きです。

入力ファイル:

a a|b b|c c|d d|e e
f f|g g|h h|i i|j j

出力ファイル:

a a|b b|c&c|d d|e&e
f f|g g|h&h|i i|j&j

cc, ee, hh and jjの間のスペースが&に置き換えられていることがわかります。while loopを使用してファイルを読み取り、cutコマンドを使用する別のソリューションがあります。区切り文字を使用して、位置に基づいて変数に格納し、sedを使用してスペースを「&」で置き換え、分割されたすべての変数を1つの変数に追加し、新しいファイルに追加します。これを達成するために使用できる単一のコマンドはありますか?

5
user7952074

これにはawkを使用します。

awk -F\| '{gsub(" ","\\&",$3); gsub(" ","\\&",$5)}1' OFS=\| infile.txt 
  • -F\|は、フィールドが|パイプで区切られていることを「awk」に通知します(\によってシェルにエスケープされないため、 pipeline stdin として解釈されません)。 -F"|"または-F'|'のいずれか)。

  • gsub("regexp","replacement"[, INDEX]) 構文を使用して、" "(スペース)をリテラル&でインデックス(列)$3$5に置き換えます。 |区切り文字に基づくインデックス位置。

    a a|b b|c c|d d|e e
    ^^^|^^^|^^^|^^^|^^^
    $1 |$2 |$3 |$4 |$5
    

    なぜ\\&が2回エスケープされたのですか?

  • 1の最後に使用されるawk '{...}1'は何ですか?印刷するのはawkのデフォルトのアクションコントロールです。 詳細を読む

  • OFS=\|は、指定された|区切り文字を使用してフィールドを再び表示または印刷します。

12
αғsнιη

あなたができる

_sed 's/\(|[^| ]*\) */\1\&/4;s//\1\&/2'
_

あなたの例のために。説明:

_|[^| ]*_は、フィールド区切り文字とその列のすべての非スペースを検索します。 \(\)でグループ化されているので、後で_\1_に置き換えてコピーできます。次に、1つ以上の空白が_&_に置き換えられます。これは、置換文字列でエスケープする必要があります。 _4_は、これを5番目の列である4番目のオカレンスに適用することを意味します。次に、3番目の列を_2_で繰り返します。空のパターンを指定してパターンを繰り返す必要はありません。

列にスペースのグループが複数あるか、まったくない場合は、さらに複雑になります。次に、awkなどの別のツールを使用することをお勧めします。

一方、各列に常に空白が1つあることがわかっている場合は、単純な

_sed 's/ /\&/5;s//\&/3'
_
8
Philippos
Perl -aF'(\|)' -lne 's/\h/&/ for @F[2*2,2*4]; print @F' input_file

結果

a a|b b|c&c|d d|e&e
f f|g g|h&h|i i|j&j

ワーキング

パイプ|で現在のレコードを分割し、フィールドに区切り文字も含めます。したがって、3番目と5番目のフィールドは2 * 2および2 * 4フィールドになります。

これらの両方のフィールドで、水平方向の空白\hをリテラル&に置き換えます。完了したら、フィールドを印刷します。

7
user218374