各行末の空白の各文字を「_」に置き換えたいのですが。空白文字をリードするための同様の質問と回答を見つけました。しかし、末尾の空白のためにそれを再構築することに失敗しました。これがリンクです: https://stackoverflow.com/questions/9222281/replace-leading-whitespace-with-sed-or-similar
誰かがより速くまたはより良い方法を考えることができれば、それも素晴らしいでしょう。私はまた、より早く学ぶことができるので、良い説明にも感謝します:)
Input:
foo bar
foo bar oof
line 3a
line fo a
Output:
foo bar_____
foo bar oof
line 3a___
line fo a_
GNU awkの3番目の引数がmatch()およびgensub()の場合):
$ awk 'match($0,/(.*[^ ])(.*)/,a){$0=a[1] gensub(/ /,"_","g",a[2])} 1' file
foo bar_____
foo bar oof
line 3a___
line fo a_
どのawkでも:
$ awk 'match($0,/ +$/){tail=substr($0,RSTART,RLENGTH); gsub(/ /,"_",tail); $0=substr($0,1,RSTART-1) tail} 1' file
foo bar_____
foo bar oof
line 3a___
line fo a_
上記のgawkソリューションを調整して、先行ブランクも置き換えるには:
$ awk 'match($0,/^( *)(.*[^ ])(.*)/,a){$0=gensub(/ /,"_","g",a[1]) a[2] gensub(/ /,"_","g",a[3])} 1' file
foo bar_____
_foo bar oof
__line 3a___
__line fo a_
GNU sedで、eolのすべてのスペースをアンダースコアに置き換えます:
sed ':x;s/ \( *\)$/_\1/;tx'
Perlを使用する方が効率的です。
Perl -lpe 's/(\s+)$/"_" x length($1)/e' input.txt
これは、ループする代わりに、行ごとに1つの置換を行うだけで、末尾に空白を挿入する必要があります。
awk -F '[ \t]+$' 'NF>1{t=substr($0,length($1)+1);gsub(/./,"_",t); $0=$1 t} 1'
これはtrailingタブとスペースの混合も扱います。フィールド区切り文字(-F
、FS
)は、スペースにのみ一致するように、または$
で末尾にアンカーされたままであれば、他の種類の非表示文字にも一致するように簡単に調整できます。
これをleading空白で機能させるには、$
から^
だけでなく、すべてをミラーリングする必要があります。
awk -F '^[ \t]+' 'NF>1{h=substr($0,1,length()-length($2));gsub(/./,"_",h); $0=h $2} 1'
先頭と末尾の両方ブランクで機能させるには、ロジックを逆にする必要があります。フィールド区切り文字を、先頭と末尾の空白に一致するパターンにしないに設定します。
awk -F '[^ \t](.*[^ \t]|$)' '{s=$0; h=gsub(/./,"_",$1); t=gsub(/./,"_",$2); print $1 substr(s,h+1, length(s)-h-t) $2}'
または調整可能なパターンで同じ:
awk -v ns='[^ \t]' 'BEGIN{FS=ns"(.*"ns"|$)"}{s=$0; h=gsub(/./,"_",$1); t=gsub(/./,"_",$2); print $1 substr(s,h+1, length(s)-h-t) $2}'
@ EdMortonのソリューション とは異なり、これらはスペースのみを含む行を正しく処理し、GNU awk(gawk)だけでなく、awkの任意の実装で機能します。例: mawkまたはbwk( "original-awk")はどちらもgawkよりもはるかに高速ですが、gawkを使用した場合でも、最後のソリューションは@EdMortonのほぼ2倍の速度になります。
Sedで私が考えることができる唯一の解決策は、ループで繰り返し置換することです。末尾のスペースと長い行が多い場合、これは遅くなる可能性があります:
sed -e :x -e 's/ \( *\)$/_\1/;tx'
sed ':x;s/ \( *\)$/_\1/;tx'
は standard sedではないことに注意してください。 :label
は、;
で終了できるコマンドの1つではありません。
編集コマンド以外
{...}
、a
、b
、c
、i
、r
、t
、w
、:
、および#
の後には、<semicolon>
、オプションの<blank>
文字、および別の編集コマンドを続けることができます。
これは、既存の Perlの回答 を実際に改善したものではない代替のPerlソリューションですが、s///
のe
フラグを使用しないため、理論的には変更できます正規表現でsedのようなs///
およびPerl/pcreのようなゼロ幅アサーションを提供する他のいくつかのツールに:
Perl -ple 's/\s(?=\s*$)/_/g'
次の簡単な方法でもこれを行うことができます:
Perlは空白以外で分割し、最後のフィールドでアンダースコアを付けるためにスペースの文字変換を実行します。次に、すべてのフィールドを印刷します。
$ Perl -F'(\S+)' -lane '
$F[-1] =~ tr/ /_/ if @F;
print @F;
' file
GNU sedを使用して、先読みと同等の処理を実行します。
$ sed -re '
y/ /\n/
:loop
s/\n(\S| )/ \1/
tloop
y/\n/_/
' file
これは正反対に機能します(\ Sを[^ [:space:]]に変更します)
$ sed -e '
h;s/\s*$//;x;s/.*\S//
y/ /_/;x;G;s/\n//
' file
このメソッドはs /// e拡張フラグを利用するため、gnu sedでのみ機能します。
$ sed -re '
s/(.*\S)(.*)/echo "\1""$(echo "\2" | tr " " _)"/e
' file
行を均等にするためにadd whitespaceをしようとしている場合:
$ cat -A file
foo bar$
foo bar oof$
line 3a $
line fo a$
線は均一ではありません
Perl -MList::Util=max -lne '
Push @lines, $_
}
END {
$wid = max map {length} @lines;
for $line (@lines) {
$padded = sprintf "%-*s", $wid, $line;
$padded =~ s/(\s+)$/"_" x length($1)/e;
print $padded
}
' file
foo bar_____
foo bar oof
line 3a___
line fo a_