各行の最後の文字を除くすべての文字を置き換える

各行の最後の文字を除くすべての文字を置き換える

「|」アイテムを変えたいです。とは別にファイルの各行に最後のスペースを入れるには、次のようにします。sedのみ。私はこのようなことを避けたい:

 sed -e "s/[|]/ /1" -e "s/[|]/ /1" -e "s/[|]/ /1" -e "s/[|]/ /1" -e "s/[|]/ /1"  -e "s/[|]/ /1" -e "s/[|]/ /1" mydata.txt

ファイル入力:

FLD1     |SFK TK |FLD2   |FLD4 |FLD5 |-          |20200515 |NNNN |406   RCO 301
FLD1     |SFK TK |FLD2   |FLD4 |FLD5 |-          |20200515 |NNNN |0
FLD1     |SFK TK |FLD2   |FLD4 |FLD5 |-          |20200515 |NNNN |0     

ファイル出力:

FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |406   RCO 301
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |0
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |0

答え1

sed ':a;/[|].*[|]/s/[|]/ /;ta' file
  • /[|].*[|]/:ラインにパイプが2本ある場合
  • s/[|]/ /:最初のものを空白に置き換えます。
  • ta:交換した場合に戻ります:a

出力:

$ sed ':a;/[|].*[|]/s/[|]/ /;ta' file
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |406   RCO 301
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |0
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |0

@steeldriverが言ったように、上記のように|基本正規表現(BRE)では単純に使用できません。拡張正規表現(ERE)を有効にするフラグをsedに追加する[|]か、またはを-E作成する必要があります。[|]\|


完全性のために、POSIX sed 仕様「除外編集」と言う{...},a,b,c,i,r,t,w,:,,そして#後ろにはセミコロンがあります。これで、上記と互換性のある代替方法は次のとおりです。

sed -e ':a' -e '/[|].*[|]/s/[|]/ /;t a' file

答え2

とは異なるアプローチクワジモドの明示的なサイクルsed:

$ sed 'h; s/.*|//; x; s/|[^|]*$//; y/|/ /; G; y/\n/|/' file
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |406   RCO 301
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |0
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN |0

各行の予約済みスペースに行を保存し、h最後の行まで含めてその行のすべての項目を削除します|。次に、行のソースを置き換えて、最後の行と|それ以降のすべての項目を削除します。

パターンスペースには元の行の最初の部分が含まれ、予約済みスペースには行の最後の部分が含まれます。

最初のy///コマンドは、残りのすべての項目を|空白に置き換えます。 G間に改行文字を使用して、パターンスペースの末尾に予約済みスペースを追加します。 2番目のy///コマンドは、対応する改行文字をaに変換して|完了します。

限られた(固定された)数の置換をs///実行し、可能であればより速いコマンドを使用することは、これが私のコンピュータで明示的なy///ループバリアント(50MiBデータで〜2.3秒、GNUループ秒を使用する同じデータで〜7.8秒)よりも速くなります実行されることを意味します。sed)。

興味深いことに、明示的なループ変更で逆参照を使用すると(Isaacと私がそうでしたように)、作業速度がさらに遅くなります(〜33秒)。イサクの変種、私の時間は〜29秒(コメントから)、上記と同じデータセットおよび条件で)。


awkこれを使うほぼ最後の区切り文字を除くすべての|区切り文字を空白に置き換えます。それ以来、「ほぼ」入れる最後の項目の前にスペースがあります|

$ awk -F '|' 'BEGIN { OFS = " " } { $NF = "|" $NF; print }' file
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN  |406   RCO 301
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN  |0
FLD1      SFK TK  FLD2    FLD4  FLD5  -           20200515  NNNN  |0

|各行を区切りフィールドセットとして読み取り、|最後のフィールドの先頭に文字を追加し、フィールド区切り文字のスペースを含む結果レコードを印刷します。

デフォルトの動作を検討してくださいawk(スペースはデフォルトの出力フィールド区切り文字であり、入力フィールド区切り文字はとして使用できますFS)。

awk -F '|' '{ $NF = FS $NF; print }' file

または@Isaacの助けを借りて、少し短くなりました。

awk -F '|' '{ $NF = FS $NF }; 1' file

答え3

Perlでは、次のように実行できます。

perl -pe 's/\|(?=.*\|)/ /g'     ex

どこ:

  • perl -peジョブ - ジョブの実行と印刷
  • \|(?=.*\|)|他の項目を含む未使用の照会に一致する正規表現。(?=.*|)|

答え4

以下は利用可能ないくつかの選択肢です。

$ sed -e '
   s/|[^|]*$/\n&/
   s/\n|/\n/
   y/\n|/| /
' file

$ perl -pe 's/\|/ / until tr/|/|/ == 1' file

$ perl -pe 'my $k=tr/|/|/; s/\|/ / while $k-->1' file

関連情報