最後の改行がファイルの最後の文字である場合に削除したいファイルがいくつかあります。 od -c
は、実行したコマンドがファイルの末尾に新しい行を書き込むことを示しています。
0013600 n t > \n
私はsedでいくつかのトリックを試しましたが、考えられる最善の方法はトリックをやっていないことです:
sed -e '$s/\(.*\)\n$/\1/' abc
これを行う方法はありますか?
Perl -pe 'chomp if eof' filename >filename2
または、その場でファイルを編集するには:
Perl -pi -e 'chomp if eof' filename
[編集者のメモ:-pi -e
はもともと-pie
でしたが、いくつかのコメントで指摘され@hvdで説明されているように、後者は機能しません。
これは、私が見たawkのWebサイトで「Perl冒asp」と説明されていました。
しかし、テストでは機能しました。
Shell コマンド置換 末尾の改行文字を削除するという事実を利用できます:
Bash、ksh、zshで動作するシンプルなフォーム:
printf %s "$(< in.txt)" > out.txt
ポータブル(POSIX準拠)代替(やや効率が悪い):
printf %s "$(cat in.txt)" > out.txt
注意:
in.txt
がmultiple改行文字で終わる場合、コマンド置換はallを削除しますそれらの-ありがとう、@ Sparhawk。 (末尾の改行以外の空白文字は削除されません。)printf %s
は、出力に改行が追加されないことを保証します(非標準のecho -n
のPOSIX準拠の代替です。 http://pubs.opengroup.org/onlinepubs/009696799/を参照してください。 Utilities/echo.html および https://unix.stackexchange.com/a/65819 )他の回答のガイド:
Perlが利用可能な場合は、 受け入れられた回答 に進みます-それはsimple and memory -efficient(入力ファイル全体を一度に読み取りません)。
それ以外の場合は、 ghostdog74'sAwk回答 -それはあいまいですが、メモリ効率も高いです; より読みやすい同等物(POSIX準拠)は次のとおりです。
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
)の設定により、最後の行をOFS
ブロックで処理できるように、印刷は1行遅延され、末尾の\n
なしで印刷されます。空の文字列に。冗長ではあるが、in-placeを実際に編集する高速で堅牢なソリューションが必要な場合(反対にオリジナルを置き換える一時ファイルを作成するには、 jrockway'sPerl script を検討してください。
GNU coreutilsのhead
を使用してこれを行うことができます。ファイルの末尾に関連する引数をサポートします。したがって、最後のバイトを使用しないでください:
head -c -1
終了改行をテストするには、tail
およびwc
を使用できます。次の例では、結果を一時ファイルに保存し、その後元のファイルを上書きします。
if [[ $(tail -c1 file | wc -l) == 1 ]]; then
head -c -1 file > file.tmp
mv file.tmp file
fi
sponge
のmoreutils
を使用して、「インプレース」編集を行うこともできます。
[[ $(tail -c1 file | wc -l) == 1 ]] && head -c -1 file | sponge file
.bashrc
ファイルにこれを詰め込むことにより、一般的な再利用可能な関数を作成することもできます。
# Example: remove-last-newline < multiline.txt
function remove-last-newline(){
local file=$(mktemp)
cat > $file
if [[ $(tail -c1 $file | wc -l) == 1 ]]; then
head -c -1 $file > $file.tmp
mv $file.tmp $file
fi
cat $file
}
コメントでKarlWilburで注記され、 Sorentar'sanswer 、truncate --size=-1
はhead -c-1
を置き換えることができ、インプレース編集をサポートします。
head -n -1 abc > newfile
tail -n 1 abc | tr -d '\n' >> newfile
編集2:
これはawk
バージョンです(修正済み)潜在的に巨大な配列を蓄積しません:
awk '{if(line)print line; line = $ 0} END {printf $ 0} 'abc
鷹
awk '{q=p;p=$0}NR>1{print q}END{ORS = ""; print p}' file
CoreutilsからのGNUエコーを必要とする単一行ファイルの非常に簡単な方法:
/bin/echo -n $(cat $file)
正しく実行したい場合は、次のようなものが必要です。
use autodie qw(open sysseek sysread truncate);
my $file = shift;
open my $fh, '+>>', $file;
my $pos = tell $fh;
sysseek $fh, $pos - 1, 0;
sysread $fh, my $buf, 1 or die 'No data to read?';
if($buf eq "\n"){
truncate $fh, $pos - 1;
}
読み取りと追加のためにファイルを開きます。追加するために開くということは、ファイルの終わりまで既にseek
edされていることを意味します。次に、tell
を使用して、ファイルの末尾の数値位置を取得します。その番号を使用して1文字を検索し、その1文字を読み取ります。改行の場合、ファイルをその改行の前の文字に切り詰めます。それ以外の場合は、何もしません。
これは、入力に対して一定の時間と一定のスペースで実行され、それ以上のディスクスペースも必要ありません。
素敵で整頓されたPythonソリューションです。ここでは簡潔にするつもりはありませんでした。
これにより、ファイルのコピーが作成され、コピーの最終行から改行が削除されるのではなく、ファイルがインプレースで変更されます。ファイルが大きい場合、これはベストアンサーとして選択されたPerlソリューションよりもはるかに高速になります。
最後の2バイトがCR/LFの場合、ファイルを2バイト切り捨て、最後のバイトがLFの場合、1バイト切り捨てます。最後のバイトが(CR)LFでない場合、ファイルを変更しようとしません。エラーを処理します。 Python 2.6でテスト済み。
これを「striplast」およびchmod +x striplast
というファイルに入れます。
#!/usr/bin/python
# strip newline from last line of a file
import sys
def trunc(filename, new_len):
try:
# open with mode "append" so we have permission to modify
# cannot open with mode "write" because that clobbers the file!
f = open(filename, "ab")
f.truncate(new_len)
f.close()
except IOError:
print "cannot write to file:", filename
sys.exit(2)
# get input argument
if len(sys.argv) == 2:
filename = sys.argv[1]
else:
filename = "--help" # wrong number of arguments so print help
if filename == "--help" or filename == "-h" or filename == "/?":
print "Usage: %s <filename>" % sys.argv[0]
print "Strips a newline off the last line of a file."
sys.exit(1)
try:
# must have mode "b" (binary) to allow f.seek() with negative offset
f = open(filename, "rb")
except IOError:
print "file does not exist:", filename
sys.exit(2)
SEEK_EOF = 2
f.seek(-2, SEEK_EOF) # seek to two bytes before end of file
end_pos = f.tell()
line = f.read()
f.close()
if line.endswith("\r\n"):
trunc(filename, end_pos)
Elif line.endswith("\n"):
trunc(filename, end_pos + 1)
追伸「Perl golf」の精神で、これが私の最短のPythonソリューションです。ファイル全体を標準入力からメモリに丸、みし、すべての改行を最後から取り除き、結果を標準出力に書き込みます。 Perlほど簡潔ではありません。このようなちょっとしたトリッキーな高速処理でPerlに勝るものはありません。
.rstrip()
の呼び出しから「\ n」を削除すると、複数の空白行を含むファイルの末尾からすべての空白が削除されます。
これを「Slurp_and_chomp.py」に入れて、python Slurp_and_chomp.py < inputfile > outputfile
を実行します。
import sys
sys.stdout.write(sys.stdin.read().rstrip("\n"))
さらに別のPerl WTDI:
Perl -i -p0777we's/\n\z//' filename
$ Perl -e 'local $ /; $ _ = <>; s/\ n $ //; print- a-text-file.txt
sedの任意の文字(改行を含む)に一致 も参照してください。
高速な解決策は、gnuユーティリティの切り捨てを使用することです:
[ -z $(tail -c1 file) ] && truncate -s-1
ファイルの末尾に改行がある場合、テストは真になります。
削除は非常に高速で、本当に適切に行われ、新しいファイルは不要であり、検索も最後から1バイトだけ読み取っています(末尾-c1)。
Perl -pi -e 's/\n$// if(eof)' your_file
Ddを使用:
file='/path/to/file'
[[ "$(tail -c 1 "${file}" | tr -dc '\n' | wc -c)" -eq 1 ]] && \
printf "" | dd of="${file}" seek=$(($(stat -f "%z" "${file}") - 1)) bs=1 count=1
#printf "" | dd of="${file}" seek=$(($(wc -c < "${file}") - 1)) bs=1 count=1
Unixファイルタイプで、これが機能する最後の改行のみが必要であると仮定します。
sed -e '${/^$/d}'
複数の改行では機能しません...
*最後の行が空白行の場合のみ機能します。
さらに別の回答FTR(そして私のお気に入り!):バックティックを介して出力をストリップしてキャプチャしたいものをエコー/キャットします。最後の改行は削除されます。例えば:
# Sadly, outputs newline, and we have to feed the newline to sed to be portable
echo thingy | sed -e 's/thing/sill/'
# No newline! Happy.
out=`echo thingy | sed -e 's/thing/sill/'`
printf %s "$out"
# Similarly for files:
file=`cat file_ending_in_newline`
printf %s "$file" > file_no_newline
POSIX SED:
$ - match last line
{ COMMANDS } - A group of commands may be enclosed between { and } characters. This is particularly useful when you want a group of commands to be triggered by a single address (or address-range) match.
私は同様の問題を抱えていましたが、Windowsファイルで作業しており、それらのCRLFを維持する必要がありました-Linuxでの私のソリューション:
sed 's/\r//g' orig | awk '{if (NR>1) printf("\r\n"); printf("%s",$0)}' > tweaked
ルビー:
Ruby -ne 'print $stdin.eof ? $_.strip : $_'
または:
Ruby -ane 'q=p;p=$_;puts q if $.>1;END{print p.strip!}'
私がこれをやりたかったのはコードゴルフのときだけで、それからコードをファイルからコピーしてecho -n 'content'>file
ステートメントに貼り付けました。
sed ':a;/^\n*$/{$d;N;};/\n$/ba' file
これは、ファイルの読み取り/出力ではなく、パイプ/リダイレクトを使用する必要がある場合に適したソリューションです。これは、単一または複数の行で機能します。末尾の改行があるかどうかにかかわらず機能します。
# with trailing newline
echo -en 'foo\nbar\n' | sed '$s/$//' | head -c -1
# still works without trailing newline
echo -en 'foo\nbar' | sed '$s/$//' | head -c -1
# read from a file
sed '$s/$//' myfile.txt | head -c -1
詳細:
head -c -1
は、文字が何であるかに関係なく、文字列の最後の文字を切り捨てます。したがって、文字列が改行で終わらない場合、文字が失われます。sed '$s/$//'
を追加します。最初の$
は、コマンドを最後の行にのみ適用することを意味します。 s/$//
は、「行末」を「何もしない」に置き換えることを意味します。これは基本的に何もしません。ただし、末尾に改行が追加されないという副作用があります。注:Macのデフォルトhead
は、-c
オプションをサポートしていません。 brew install coreutils
を実行し、代わりにghead
を使用できます。
sed -n "1 x;1 !H
$ {x;s/\n*$//p;}
" YourFile
ファイル内の最後の\ nを削除する必要があります。 sedバッファーの制限により、巨大なファイルで動作しない