最後のx個の出現を除く文字を置き換えます


9

次のようなIPに関連付けられた一連のホスト名を持つファイルがあります。

x-cluster-front-1 192.168.1.2
x-cluster-front-2 192.158.1.10
y-cluster-back-1 10.1.11.99
y-cluster-back-2 10.1.157.38
int.test.example.com 59.2.86.3
super.awesome.machine 123.234.15.6

次のようにしたい:

x-cluster-front-1 192.168.1.2
x-cluster-front-2 192.158.1.10
y-cluster-back-1 10.1.11.99
y-cluster-back-2 10.1.157.38
int-test-example-com 59.2.86.3
super-awesome-machine 123.234.15.6

どうすれば交換できますか?(ドット)最初の列から-(ハイフン)を付けて、2番目の列によるソートを容易にしますか?最初のスペースまでsedを使用してドットを置き換えるか、最後の3つを除くすべてのドットを置き換えることを考えていましたが、正規表現とsedを理解できません。単純な置換を実行できますが、これは私の頭の上の方法です!

これは、私がbashで書いている大きなスクリプトの一部です。この部分で行き詰まっています。

回答:


7

AWKを使用できます

awk '{gsub(/-/,".",$1);print}' infile

説明

awkデフォルトでは、空白で行を分割します。このように、(行の最初の列$1awk-ese)を使用すると、上の置換を実行したいものになります。この目的のために、以下を使用できます。

 gsub(regex,replacement,string)

必要な置換を実行します。

gsubのためにのみサポートされていますgawkし、nawk多くの近代的なディストリビューションには、awkソフト・リンクにありますgawk


1
+1私を殴ってください。説明は、質問者と将来の読者にも本当に役立つと思います。
ジョセフR.

1
@JosephR。申し訳ありませんが、私は説明が得意ではないが、私は..しようとした更新しました
ラーフルパティル

2
のPOSIX仕様awkはに基づいているnawkため、最近のすべてのawk実装でを使用する必要がありgsubます。Solarisでは、/usr/xpg4/bin/awkまたはが必要になる場合がありますnawk
ステファンChazelas

@RahulPatilよろしければ、他の人の役に立つと思う行をいくつか追加しました。
ジョセフR.

@JosephRありがとう..、それは今完璧だと思います.. :)
Rahul Patil 14年

6

最初のフィールドで置換を行う必要がある場合は、Rahulのawkソリューションを使用するのが最善ですが、間隔に影響する可能性があることに注意してください(フィールドの間に単一のスペースを入れてフィールドを書き換えます)。

代わりにそれを書くことでそれを避けることができます:

perl -pe 's|\S+|$&=~tr/./-/r|e' file

この-pフラグは、「入力ファイルを1行ずつ読み取り、指定されたスクリプトを適用した後、各行を出力する」ことを意味します-e。次に、すべてをで置き換えた後、s|pattern|replacement|スペース以外の文字の最初のシーケンス(\S+)を一致したパターン($&)で置き換えます。トリックは、演算子が式を置換として評価する場所で使用することです。そのため、前の置換()の一致()に1つの置換()を適用できます。.-s|||eetr/./-/$&s|||e

あなたは、すべてを置換する必要がある場合.-GNUで、最後の3つの最後のものを除いてsed、あなたが持っていると仮定するとrev、コマンドを:

rev file | sed 's/\./-/4g' | rev

1
Perlソリューションは、バージョン5.14以降を想定しています(が機能する/rため)。
ジョセフR.

3

Sedは、この仕事に最も簡単なツールではありません。他の回答でより良いツールを参照してください。

交換する.ことにより、-第一の空間にまでしか、使用sループインチ

sed -e '
  : a                     # Label "a" for the branching command
  s/^\([^ .]*\)\./\1-/    # If there is a "." before the first space, replace it by "-"
  t a                     # If the s command matched, branch to a
'

(一部のsed実装は、同じ行のコメントをサポートしていません。GNUsedはサポートしています。)

代わりに最後のスペースまで置換を実行するには、次のようにします。

sed -e '
  : a                     # Label "a" for the branching command
  s/\.\(.* \)/-\1/        # If there is a "." before the last space, replace it by "-"
  t a                     # If the s command matched, branch to a
'

別の手法では、sedのホールドスペースを利用します。変更したくないビットをホールドスペースに保存し、作業を行ってから、ホールドスペースを呼び出します。ここでは、最後のスペースで行を分割し、最初の部分でドットをダッシュ​​に置き換えます。

sed -e '
  h           # Save the current line to the hold space
  s/.* / /    # Remove everything up to the last space
  x           # Swap the work space with the hold space
  s/[^ ]*$//  # Remove everything after the last space
  y/./-/      # Replace all "." by "-"
  G           # Append the content of the hold to the work space
  s/\n//      # Remove the newline introduced by G
'

2

Rahulがあなたユースケースの標準的な回答を提供してくれので、私は定型的な問題への挑戦を試しみようと思いました:正規表現の最後のx個の出現以外をすべて置き換えます:

perl -pe '
    $count = tr{.}{.}; # Count '.' on the current line
    $x = 3;
    next LINE if $count <= $x;
    while(s{\.}{-}){   # Substitute one '.' with a '-'
        last if ++$i == $count - $x # Quit the loop before the last x substitutions
    }
$i = 0
' your_file

上記のコード(テスト済み)は、スペースで区切られたフィールドがあることを想定していません。最後の3つのドットを除いて、ライン上のすべてのドットをダッシュ​​に置き換えます。3コード内のをお好みに置き換えます。


2

これには、さまざまなツールを使用できます。Rahul Patilがすでにあなたにgawk1つを与えているので、他にいくつかあります:

  • perl

    perl -lane  '$F[0]=~s/\./-/g; print "@F"' file
    

    この-aスイッチにより、perlは入力行を空白で自動的に分割し、結果のフィールドを配列に保存します@F。最初のフィールドは、それゆえになります$F[0]我々は交換するように、( s///)のすべての出現.との-最初のフィールドで、その後は、配列全体を印刷します。

  • シェル

     while read -r a b; do printf "%s %s\n" "${a//./-}" "$b"; done < file 
    

    ここでは、whileループがファイルを読み取り、空白で自動的に分割されます。これにより、2つのフィールド$firstとが作成されます$rest。構築物は、${first//pattern/replacement}出現するすべての置き換えpatternではreplacement


+1 はperlrun(1)それ-aが「自動分割モード」であることを教えてくれますが、私はそれを「awkモード」と考えるのが好きです:D
ジョセフR.

2

これは、大きな厄介な正規表現よりも少し読みやすいと思います。基本的には、行を空白で2つのフィールドに分割し、最初の部分でsedを使用します。

while read -r host ip; do
    echo "$(sed 's/\./-/g' <<< "$host") $ip"
done < input_file

シェルによっては、sedコマンドの代わりに$ {host //./-}を使用することもできます。


0
sed 's/\./-/' <file name>

gコマンドの最後で使用せずにこれを行うことができます...これは、パターンの最初の出現を置き換えるだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.