sedコマンドを使用してLinuxの各行の最後の単語を出力できますか?


9

以下の行で構成されるファイルがある場合、

12345 567 7878 66

   er3 t45t y6y46y 


 4年6年656年5年

   46年6年65年7年66年

 yy46y6y

出力は次のようになります。

66

y6y46y

y5y

y66uyuyy

y46y6y

コマンドsed 's/.* //g'ファイル名と他のいくつかのsedコマンドを試しましたが、機能しません。

正確なsedコマンドは何ですか?


使用する必要がありますsedか?
coffeMug ​​2015年

回答:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

それでもすべての空白行に空行が出力されます。それを避けるには:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

単一の表現の代替:sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'
jimmij 2015年

@jimmij-最後の空白でないシーケンスも最初であり、その前に空白がない場合は機能しません。また、.*たぶん最後尾だけでもよいでしょう-とにかく、末尾の空白以外は除外します.*[^[:blank:]]
mikeserv、2015年



4

あと少しです。最後の単語を指定するだけです:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

それがすること:

  1. '^。*'は、行頭およびスペース内のすべてを削除します。
  2. '\(...)\'はパターンに一致し、\ 1として返します。
  3. '[^]'は、スペースを含まないものに一致します。

(より良いソリューションを追加するために編集。Hildredに感謝!)


1
以下に短い表現を示します。sed -r 's/.* ([^ ]+)/\1/g'拡張正規表現が許可されている場合は、通常そうです。
mkalkov 2015年

保持したいものではなく、保持したくないものを置き換えて、より短いバージョン:sed 's/.* //'
Uriel

2

たとえば、のgrep代わりにの適切なパターンを使用できsedます。

grep -o "[a-Z0-9]*$"

この例では[...]、「単語」に適していると考えられる文字の範囲が含まれています(この場合は英数字、他の記号を追加できますが、一部はエスケープする必要があります)。


2
これは、行の終わりに空白がないことを前提としています。a-ZASCIIベースのロケールであっても、範囲はあまり意味がありません。これ-oはGNU拡張機能であることに注意してください。
ステファンChazelas

0

単語を修飾して1つ以上の非空白文字のシーケンスを意味する場合、答えは間違いなくあり、それも非常に簡単に行われます。これは、[[:blank:]]*[^[:blank:]]*はブール値の補完であり、文字列内のすべての文字が完全な場合、[[:blank:]]*U [^[:blank:]]*は可能な文字列をほとんど同じ方法で記述できるため.*です。

不完全な文字やその他の無効なバイトシーケンスが文字列内に存在する場合、文字列を誤ったエンコーディングで解釈する場合に発生する可能性があるように、先頭から最後まで正常に記述できません。文字列のバイトごとに完全な文字を確保するには、Cロケールを次のように強制できます。

LC_ALL=C sed ...

... .*またはなどの包括的なパターンで頭から尾まで文字列を記述する問題を回避します([ ]*[^ ]*)*

完全に相補的なパターンは、文字列の長さを左から右に必要なだけ繰り返すことができ、パターンが途切れることなく最後に発生する可能性のある場所に到達します。これは間違いなく通常の言語です。

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

これらのバージョンはどちらも空白行を印刷します。これは、Kleene *スターがパターンの0回以上の出現に一致するためです。最初に0個以上の空白でない文字に一致し、次に0個以上の空白文字に一致し、次に文字列全体に一致するまで、グループ化された一致の0個以上に一致します。

このすべてを一致したので、魔法が交換に起こる-参照はグループによって返される\1\2、それぞれの最後に出現しています。そのため、置換が行われると、すべての文字列は、ゼロ以上の空白文字ではない行の最後の出現のみ、またはサブグループに置き換えられ\2ます。

もちろん、これはすべての可能な文字列(空の文字列でも)に対して機能します。つまり、両方のフォームが空白文字のみを含むか、まったく含まない行の改行文字を印刷します。これを処理するためにできることは2つありますが、最初に文字クラスを少し入力しやすくします。

b='[:blank:]'

ここで、行に空白ではない文字が1つ以上含まれている場合にのみ印刷するには、次のようにします。

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. BREケース-置換は常に実行され、少なくとも1文字が残っているパターンスペースのみが出力されます。
  2. EREケース-置換は、少なくとも1つの非ブランク文字を含むパターン・スペースでのみ試行されます。

構文が正しい限り、どちらの形式でもどちらの方法でも機能します。

-nパターンスペースのスイッチを無効にし、自動印刷、pにフラグs///ubstitutionまたは/アドレス/コマンドは、成功した場合、その結果を印刷します。

これと同じロジックを適用して、{num}次のような任意の発生を取得することもできます。

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

... num両方の正規表現のを数字で置き換えると、{num}空白文字ではない一連の指定されたオカレンスのみを出力できます。ここでは、文字列の先頭のスペースがカウントされないように、少し異なる形式が使用されています。

なお-EへEREスイッチsed、それはないですが、BSDやGNUバージョンの両方でサポートされて POSIX標準の構文。


素晴らしい説明、素晴らしいハックですが、これは従来の sed実装(Solaris / usr / bin / sedなど)では機能せず、より単純なアプローチ(25行を超える入力行でメモリを使い果たす)よりも高価になることに注意してください。sed_su3例えば家宝toolchestから)。だから、私は答えが好きですが、私はそのアプローチを勧めません。
ステファンChazelas

FreeBSDでも動作しないようです。
ステファンChazelas

@StéphaneChazelas-ええ、パフォーマンスはこのようなものには本当にひどいですが、番号付きのオカレンスを見つけるのに非常に効果的です。また、行末のケースの方s/.* \([^[:blank:]]\{1,\}\).*/\1/がはるかに優れていますが、複数の行が関係している場合はさらに困難です。しかし、つい先日、私はそれ's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]をかなり効果的に補強できることを発見しました。とにかく、ロジックに明白なエラーがない限り、私は満足しています-私は何かを逃したに違いないと思いました。
mikeserv 2015

@StéphaneChazelas-ああ、そして古いseds について-それは少し変です-それは標準に従って健全でなければなりません。xratは言います... 標準の開発者は、特定の実装の"\n*""\n\{min,max\}", "\(...\)*""\(...\)\{min,max\}"
mikeserv 2015

@StéphaneChazelas-そして、標準は言う... アスタリスク( '*' )または区間式(項目(5)を参照)のために、後方参照によって参照される部分式が複数の文字列と一致する場合、後方参照は最後の(右端の)これらの文字列の。私はこれをw /でテストしたと確信してminisedいます- minisedとにかく、私は先日w /変なものをテストしていました。
mikeserv 2015

-1

はい。次のsedコマンドは、最初にすべての末尾の空白(s/ *$//)を削除してから、最後の空白(s/.* //)までをすべて削除します。[[:blank:]]タブやその他のスペースのような文字をキャプチャするために、リテラルの空白を置き換えることはおそらく価値があります。

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

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