各行から最後の単語を取得する
1. 概要
Linuxコマンドラインでファイルを処理する場合、各行から最後の文字を削除するなど、入力ファイルの各行を操作する必要があることがよくあります。
今回は、別の問題を見てみましょう。各行から最後の単語を抽出することです。
2. 問題の紹介
2.1. 入力例
例は、問題をすばやく理解するのに常に役立ちます。
まず、入力ファイルを見てみましょう。
$ cat input.txt
Linux rocks!
Next line is an empty line:
I have trailing spaces:
I have a number: 42
input.txtには数行のテキストがあります。
さらに、ファイルには空の行と末尾にスペースがある1行が含まれています。 ただし、この情報は上記の出力ではそれほど明白ではありません。
-eオプションを指定したcatコマンドは、各行の終わりに「$」記号を出力します:
$ cat -e input.txt
Linux rocks!$
Next line is an empty line:$
$
I have trailing spaces: $
I have a number: 42$
これで、出力の末尾のスペースをはっきりと確認できます。
「各行から最後の単語を抽出する」という私たちの目標をもう一度見てみましょう。これは十分に明らかなようです。 ただし、注意が必要なことがいくつかあります。
2.2. 単語の定義
単語にはさまざまな定義があります。
- 単語は英語の単語を意味する場合があります—「ab_cd_1234」のような文字列はカウントされません。
- 単語は、正規表現「 \ w+」に一致する文字列です。 つまり、英数字(大文字と小文字を問わず、文字または数字)またはアンダースコア文字(「 _ 」)のみが含まれます。 たとえば、「 ab_cd_1234 」は正規表現の単語ですが、「 ab.cd#1234」はそうではありません。
- 単語は、空白以外の文字の組み合わせです。 たとえば、「 ab_cd_1234」と「ab.cd#1234」はどちらも単語です。
「単語」の定義は、問題の解決に影響します。 したがって、このチュートリアルでは、上記のリストの最後の1つを「単語」の定義として使用します。
2.3. トレーリングスペースの処理
要件に応じて、行に末尾のスペースが含まれている場合、問題には2つの異なるバリエーションがあります。
- 結果として空の文字列を返します。
- 最後の非空白文字シーケンスを返します。 行全体が空白または空の場合、結果として空の文字列が必要になります。
このチュートリアルでは、両方のバリアントについて説明し、問題を解決するための2つのアプローチについて説明します。
次に、それらの動作を見てみましょう。
3. sedコマンドの使用
sed は、非対話型のストリーム編集ユーティリティです。 この素晴らしいツールを使用して問題を解決する方法を見てみましょう。
3.1. 末尾のスペース:空の文字列を取得する
sed コマンドの問題を解決するためのアイデアは、スペースやタブなど、行の最後の水平方向の空白文字まですべてを削除することです。
sedの「s/ pattern / replace / 」コマンドは、この問題を解決するのに適しています。
$ sed 's/.*[[:blank:]]//' input.txt | cat -e
rocks!$
line:$
$
$
42$
上記の例が示すように、sedの出力をcat-e コマンドにパイプ処理して、空白文字をより簡単にチェックできるようにしました。
出力は私たちが期待しているものです。 また、空の行と末尾にスペースがある行の場合、単語として空の文字列を使用していることに気付きました。
[:blank:]はPOSIX標準文字クラスであることにも言及する価値があります。
このチュートリアルではGNUsed を使用しているため、 [[:blank:]]の代わりに「\ s 」を使用すると、ソリューションは次のようになります。同様に動作します。 ただし、POSIX標準文字クラスを使用すると、ソリューションの移植性が最も高くなります。
3.2. 末尾のスペース:空白以外の最後の文字シーケンスを取得する
問題の最初の変形を解決した場合、この問題を解決することは私たちにとって課題ではありません。
前処理ステップを追加することで、最初のソリューションを拡張できます。つまり、末尾のスペースをすべて削除します。
簡単に言うと、最初に行を右トリミングしてから、「 s/.*[[:blank:]]//」置換コマンドを適用できます。
$ sed 's/[[:blank:]]*$//; s/.*[[:blank:]]//' input.txt | cat -e
rocks!$
line:$
$
spaces:$
42$
ここでも、sedの出力をcat-e コマンドにパイプして、空白文字を確認しました。
上記の出力が示すように、入力ファイルの空の行には空の文字列があり、末尾にスペースがある行には、最後の非空白文字シーケンス(“
4. awkコマンドの使用
awk は、Linuxコマンドラインにあるもう1つの強力なテキスト処理ツールです。
sed と同様に、 awk コマンドは、置換関数 sub()および gsub()を提供します。 したがって、ここでも同じ考えを持って問題を解決することができます。
ただし、 awkはデフォルトで、フィールドベースの入力を適切にサポートします。 たとえば、行の各単語をフィールドとして見ることができます。
したがって、要件が最後の単語を抽出することである場合は、awkに最後のフィールドを返すように要求するだけです。
ただし、問題の awk ソリューションを検討する前に、数分かけてawkのFS変数を詳しく見ていきましょう。
4.1. awk FS変数の概要
awk は、 FS 変数の値を定義方法に応じて異なる方法で処理し、FSは3つの異なる方法で定義できます:
- 空の文字列として
- 単一の文字として
- 複数のキャラクターとして
awkが各ケースをどのように処理するかを見てみましょう。
まず、 FSが空の場合、入力レコードの各文字はフィールドになります。
$ awk 'BEGIN{FS=""}{print $1,$2,$3}' <<< "AWK"
A W K
次に、 FSが単一文字の場合、リテラル文字は区切り文字になります。
$ awk 'BEGIN{FS="*"}{print $1,$2,$3}' <<< "A*W*K"
A W K
ただし、この場合は例外があります。
FSが単一のスペース文字であり、これがデフォルト値でもある場合、区切り文字は正規表現の区切り文字「[[:space:]]+」または「[[\t \n]]+」と同じになります。 :
$ awk 'BEGIN{FS=" "}{print $1,$2,$3}' <<< " A W K "
A W K
第3に、 FSの値が空でないか、1文字でない場合、awkはそれを正規表現として扱います:
$ awk 'BEGIN{FS="[#@]"}{print $1,$2,$3}' <<< "A#W@K"
A W K
それでは、FS変数を調整して問題を解決する方法を見てみましょう。
4.2. 末尾のスペース:空の文字列を取得する
行の末尾に空白文字が含まれている場合や空白の場合に結果として空の文字列を使用する場合は、awkのFS組み込み変数を水平方向に設定する必要があります。空白文字クラス:
$ awk -F'[[:blank:]]' '{print $NF}' input.txt | cat -e
rocks!$
line:$
$
$
42$
FS変数を’\ s ‘で設定すると、広く使用されているGNU awkなどの一部のawk実装で機能することに注意してください。 。
ただし、バックスラッシュをエスケープする必要があります: awk -F’\\ s”{print $ NF}’input.txt。 それ以外の場合、awkは’\s‘をリテラル’s‘として扱います。
4.3. 末尾のスペース:空白以外の最後の文字シーケンスを取得する
この問題の変形を解決するために、よりコンパクトなawkワンライナーを作成できます。
$ awk '{print $NF}' input.txt | cat -e
rocks!$
line:$
$
spaces:$
42$
ご覧のとおり、期待どおりの出力が得られています。
上記のawkコマンドでは、FS変数を設定しなかったことがわかります。 つまり、デフォルト値のFSを使用します。
学習したように、デフォルトの FS は、フィールドから先頭と末尾の空白文字を削除します。 したがって、短いワンライナーがその役目を果たします。
5. 結論
この記事では、ファイルの各行から最後の単語を取得する2つの方法について説明しました。
sed を使用すると、その置換コマンドを使用して問題を解決できます。 awk コマンドを実行すると、 FS 変数を調整して、最後のフィールドを簡単に取得できます。