回答:
これはうまくいくはずです:
printf "one\ntwo\n" | awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}' ; echo " done"
スクリプトは常に現在ではなく前の行を出力し、最後の行は別の方法で処理されます。
詳細は次のとおりです。
NR>1{print PREV}
前の行を印刷します(初回を除く)。{PREV=$0}
現在の行をPREV
変数に格納します。END{printf("%s",$0)}
最後に、改行なしで最後の行を印刷します。また、これにより、末尾の空行が最大で1行削除されることに注意してください(の削除はサポートされていません"one\ntwo\n\n\n"
)。
とまったく同じものが必要な場合chomp
、私の頭に浮かぶ最初の方法は、LatinSuDがすでに投稿したawkソリューションです。実装されないが、よく使用されるchomp
いくつかの一般的なタスクを実装する他のいくつかのメソッドを追加しますchomp
。
変数にテキストを入れると、最後の改行がすべて削除されます。したがって、これらすべてのコマンドは同じ単一行の出力を生成します。
echo "$(printf 'one\ntwo') done"
echo "$(printf 'one\ntwo\n') done"
echo "$(printf 'one\ntwo\n\n') done"
echo "$(printf 'one\ntwo\n\n\n\n\n\n\n\n\n\n') done"
ファイルまたはコマンドの出力の最後の行にテキストを追加する場合は、sed
便利です。GNU sedおよびその他の最新の実装では、入力が改行で終わっていなくても、これは機能します¹; ただし、改行がまだない場合、これは改行を追加しません。
sed '$ s/$/ done/'
¹ ただし、これはすべてのsed実装では機能しません。sedはテキスト処理ツールであり、空ではなく、改行文字で終わらないファイルはテキストファイルではありません。
chomp
は、LatinSuDがすでに投稿したawkソリューションです。しかし、多くの場合chomp
、これは仕事をするための単なるツールであり、いくつかの一般的なタスクを実行する方法を提供します。これを明確にするために回答を更新しましょう。
別のperl
アプローチ。これは入力全体をメモリに読み込むので、大量のデータにはお勧めできません(cuonglmまたはそのawk
アプローチを使用してください)。
$ printf "one\ntwo\n" | perl -0777pe 's/\n$//'; echo " done"
one
two done
私はこれをgithubレポからどこかに引っ掛けましたが、どこにあるのかわかりません
#!/bin/bash
#
# Delete all trailing blank lines.
# From http://sed.sourceforge.net/sed1line.txt
#
# Version: 1.3.0
# Created: 2011-01-02
# Updated: 2015-01-25
# Contact: Joel Parker Henderson (joel@joelparkerhenderson.com)
# License: GPL
##
set -euf
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'
改行なしで行を印刷し、印刷する別の行がある場合にのみ改行を追加します。
$ printf 'one\ntwo\n' |
awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
ファイルで作業している場合は、ファイルから1文字を切り捨てることができます(改行で終わっている場合)。
removeTrailNewline(){[[$(tail -c 1 "$ 1")]] || truncate -s-1 "$ 1"; }
ファイルから1文字だけtruncate
を読み取り、ファイル全体を読み取らずに直接削除する()必要があるため、これは高速なソリューションです。
ただし、stdin(ストリーム)からのデータを処理している間は、データをすべて読み取る必要があります。そして、それを読むとすぐに「消費」されます。バックトラックなし(切り捨てと同様)。ストリームの終わりを見つけるには、ストリームの終わりまで読み取る必要があります。その時点では、入力ストリームに戻る方法はありません。データはすでに「消費」されています。これは、ストリームの最後に一致するまでデータを何らかの形式のバッファに格納してから、バッファ内のデータで何かを行う必要があることを意味します。
最も明白な解決策は、ストリームをファイルに変換し、そのファイルを処理することです。しかし、質問はストリームのある種のフィルターを要求します。追加ファイルの使用についてではありません。
素朴な解決策は、入力全体を変数に取り込むことです。
FilterOne(){ filecontents=$(cat; echo "x"); # capture the whole input
filecontents=${filecontents%x}; # Remove the "x" added above.
nl=$'\n'; # use a variable for newline.
printf '%s' "${filecontents%"$nl"}"; # Remove newline (if it exists).
}
printf 'one\ntwo' | FilterOne ; echo 1done
printf 'one\ntwo\n' | FilterOne ; echo 2done
printf 'one\ntwo\n\n' | FilterOne ; echo 3done
sedを使用すると、ファイル全体をメモリに読み込むことができます。sedでは、最後の行の末尾の改行を回避することは不可能です。GNU sedは、末尾の改行の印刷を回避する可能性がありますが、ソースファイルにすでにそれがない場合のみです。つまり、単純なsedは役に立ちません。
-z
オプション付きのGNU awkを除いて:
sed -z 's/\(.*\)\n$/\1/'
awk(任意のawk)を使用して、ストリーム全体を丸呑みにしprintf
ます。
awk ' { content = content $0 RS }
END { gsub( "\n$", "", content ); printf( "%s", content ) }
'
ファイル全体をメモリにロードすることは良い考えではないかもしれません、それは多くのメモリを消費するかもしれません。
awkでは、前の行を変数に格納して現在の行を出力することにより、ループごとに2行を処理できます。
awk 'NR>1{print previous} {previous=$0} END {printf("%s",$0)}'
しかし、私たちはもっとうまくやることができました。
現在の行を改行なしで印刷し、次の行が存在する場合にのみ改行を印刷する場合、一度に1行ずつ処理し、最後の行には後続の改行がありません。
awk 'NR == 1 {printf( "%s"、$ 0);次へ}; {printf( "\ n%s"、$ 0)} '
または、他の方法で書かれています:
awk 'NR>1{ print "" }; { printf( "%s", $0 ) }'
または:
awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'
そう:
$ printf 'one\ntwo\n' | awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
chomp
れchomp
ないため、これはとまったく同じではありません。