いくつかの出力の各行から先頭と末尾の空白をトリミングするにはどうすればよいですか?


155

出力の各行から先頭と末尾のスペースとタブをすべて削除したいと思います。

trim出力をパイプすることができるような簡単なツールはありますか?

サンプルファイル:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 

1
ここで改行を削除する解決策を探している人には、それは別の問題です。定義により、改行は新しいテキスト行を作成します。したがって、テキスト行に改行を含めることはできません。質問したいのは、文字列の先頭または末尾から改行を削除する方法:stackoverflow.com/questions/369758、または空白行または空白だけの行を削除する方法:serverfault.com/questions/252921
トニー

回答:


200
awk '{$1=$1;print}'

以下:

awk '{$1=$1};1'

先頭と末尾のスペースまたはタブ文字1 トリミングし、タブとスペースのシーケンスを1つのスペースに絞り込みます。

あなたはのいずれかに何かを割り当てるときので、それは働くawk(で印刷されたとしてレコード全体を再構築print)(すべてのフィールドを結合することにより$1、...、$NFと)OFS(デフォルトはスペース)。

1(およびロケールとawk実装に応じて他の空白文字)


2
2番目の例のセミコロンは不要です。以下を使用できますawk '{$1=$1}1'
ブライアン


興味深い... gawk、mawk、OS Xのawkではセミコロンはサポートされていません。(少なくとも私のバージョン(それぞれ1.2、4.1.1、および20070501))
ブライアン

1
私がこのアプローチについて気に入らない唯一のことは、行内の繰り返しスペースを失うことです。たとえば、echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly

2
echo ' hello ' | xargs
JREAM

44

GNUを使用している場合、コマンドは次のように要約できますsed

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

上記のコマンドが実行中です。

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

を使用hexdumpして、sedコマンドが目的の文字を正しく削除していることを確認できます。

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

キャラクタークラス

次のようなセットを文字通りリストする代わりに、文字クラス名を使用することもできます[ \t]

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

正規表現(regex)を使用するGNUツールのほとんどは、これらのクラスをサポートしています。

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

リテラルセットの代わりにこれらを使用することは、常にスペースの無駄のように思えますが、コードの移植性や、別の文字セット(国際的なことを考える)に対処する必要がある場合は、クラス名を使用することをお勧めします代わりに。

参照資料


は、一般的な場合(Unicodeなど)[[:space:]]と同等ではないことに注意してください[ \t][[:space:]]おそらくはるかに遅くなります(Unicodeには、' 'and だけでなく、より多くの種類の空白があります'\t')。他のすべてのために同じこと。
オリビエデュラック

sed 's/^[ \t]*//'ポータブルではありません。事実、POSIXは一連のスペース、バックスラッシュ、またはt文字を削除することさえ要求し、それはGNU が環境にいるsedときにも行うPOSIXLY_CORRECTことです。
ステファンシャゼラス

改行文字をトリミングしたい場合はどうすればよいですか?'\ n \ nテキスト\ n \ n'
ユージンビリコフ

awkソリューションのように他の副作用がないため、sedソリューションが気に入っています。最初のバリエーションは、OSX jsutでbashで試したときに機能しませんが、文字クラスバージョンは機能します。– sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
トニー

@EugeneBiryukov元の投稿
トニー

23

受け入れられた答えでステファンチャゼラスが示唆した
ように、スクリプトを作成できます/usr/local/bin/trim

#!/bin/bash
awk '{$1=$1};1'

そのファイルに実行権を与えます。

chmod +x /usr/local/bin/trim

これでtrim、たとえば、すべての出力を渡すことができます。

cat file | trim

(以下のコメントについて:私は以前これを使用しました:while read i; do echo "$i"; done
これもうまくいきますが、パフォーマンスが低下します)


1
ファイルが大きい場合やバックスラッシュが含まれている場合は幸運を祈ります。
don_crissti

1
@don_crissti:もう少しコメントしてもらえますか?巨大なファイルに適したソリューションはどれですか?また、ファイルにバックスラッシュが含まれている場合、どのようにソリューションを変更できますか?
rubo77

3
あなたは使用する必要がありますwhile read -r lineバックスラッシュを保存するようにし、その後も...。巨大なファイル/速度に関しては、実際、最悪のソリューションを選択しました。そこにもっと悪いことはないと思います。なぜシェルループを使用してテキストを処理するのが悪いのかに関する回答を参照してください速度ベンチマークへのリンクを追加した最後の回答に対する私のコメントを含みます。ここでのsed答えは完全に素晴らしいIMOであり、はるかに良いですread
don_crissti

@don_crissti ...および/または-1つ以上のe、Eまたはn文字の組み合わせで始まる行があり、NUL文字を含む。また、最後の改行の後の非終了行はスキップされます。
ステファンシャゼル

1
/ etc / profile(または〜/ .bashrcまたは〜/ .zshrcなど)にエイリアスを追加することもできます。alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
ジェフクレイトン

22

引数のないxargsはそれを行います。

例:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
また、これは質問内で要求されなかった行内の複数のスペースを縮小します
ロアイマ

1
@roaima-trueですが、受け入れられた回答はスペースを絞ります(質問では要求されませんでした)。ここでの本当の問題はxargs、入力にバックスラッシュと一重引用符が含まれていると配信に失敗することだと思います。
don_crissti

@don_crisstiは、受け入れられた回答が質問どおりに正しく回答するという意味ではありません。しかし、この場合、受け入れられた答えではそうだったのに対し、ここでは警告としてフラグが立てられていませんでした。将来の読者に関連する場合に備えて、事実を強調したい。
ロアイマ

また、一重引用符、二重引用符、バックスラッシュ文字で区切ります。また、1つ以上のecho呼び出しを実行します。一部のエコー実装では、オプションやバックスラッシュも処理されます...これは、単一行の入力に対してのみ機能します。
ステファンシャゼラス

17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

シェル変数に行を読み込んでいる場合、特に指示がない限り、それreadを既に実行しています


1
+1 read。読み取り中にパイプすると、動作します:cat file | while read i; do echo $i; done
rubo77

1
@ruboを除き、引用符で囲まれていない変数もシェルによって再処理されます。echo "$i"の真の効果を見るために使用read
ロアイマ

13

行を変数として保存する場合、bashを使用してジョブを実行できます。

文字列から先頭の空白を削除します。

shopt -s extglob
echo ${text##+([[:space:]])}

文字列から末尾の空白を削除します。

shopt -s extglob
echo ${text%%+([[:space:]])}

文字列からすべての空白を削除します。

echo ${text//[[:space:]]}

文字列からすべての空白を削除することは、(問題のように)先頭と末尾の両方のスペースを削除することと同じではありません。
催眠術

最良のソリューション-これは、bashビルトインのみを必要とし、外部プロセスフォークは必要ありません。
user259412

2
いいね スクリプトは、外部プログラム(awkやsedなど)を取り込む必要がない場合、LOTをより速く実行します。これは、kshの「最新」(93u +)バージョンでも機能します。
user1683793

9

「パイプ」ツールのおかげで、指定された行からすべての先行スペースと後続スペースを削除するには、完全に同等ではない3つの異なる方法を識別できます。これらの違いは、入力行の単語間のスペースに関係します。予想される動作に応じて、選択を行います。

違いを説明するために、このダミーの入力行を考えてみましょう。

"   \t  A   \tB\tC   \t  "

tr

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

tr本当にシンプルなコマンドです。この場合、スペースまたはタブ文字は削除されます。

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk 先頭と末尾のスペースを削除し、単語間のスペースごとに1つのスペースに絞り込みます。

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

この場合、sed単語間のスペースに触れることなく、先頭と末尾のスペースを削除します。

リマーク:

1行に1ワードの場合tr、仕事をします。


ただし、このいずれも末尾/先頭の改行を
削除し

(予想外の)出力を伴うソリューションのリストについては+1。
トニー

@ user61382これはかなり遅いですが、元の投稿に対する私のコメントをご覧ください。
トニー

@highmaintenance:[:space:][:blank:]の代わりにを使用して、コマンドのtrように、:... | tr -d [:space:]も改行を削除します。(参照:man tr
tron5

6

sedはそのための優れたツールです。

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

あなたはあなたのケースにそれを使用することができます。

<file sed -e 's/^[[...

またはsed、GNU の場合は「インライン」で操作します。

sed -i 's/...' file

しかし、この方法でソースを変更することは「危険」です。正しく動作しない場合(または動作する場合でも)回復できない可能性があるため、最初にバックアップ(または-i.bak一部のBSDに移植できる利点がある使用sed) !



0

トリミングしようとしている文字列が短く連続的/連続的である場合、任意のbash関数のパラメーターとして単純に渡すことができます。

    trim(){
        echo $@
    }

    a="     some random string   "

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