「|」アイテムを変えたいです。とは別にファイルの各行に最後のスペースを入れるには、次のようにします。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