ファイル内の最後の文字である場合、最後の改行を削除したいファイルがいくつかあります。 od -c
私が実行したコマンドがファイルに最後の新しい行を書き込むことを示しています:
0013600 n t > \n
私はsedを使っていくつかのトリックを試しましたが、考えられる最善の方法はそのトリックを行わないことです。
sed -e '$s/\(.*\)\n$/\1/' abc
これを行う方法はありますか?
\n
、Linuxでは1文字です
ファイル内の最後の文字である場合、最後の改行を削除したいファイルがいくつかあります。 od -c
私が実行したコマンドがファイルに最後の新しい行を書き込むことを示しています:
0013600 n t > \n
私はsedを使っていくつかのトリックを試しましたが、考えられる最善の方法はそのトリックを行わないことです。
sed -e '$s/\(.*\)\n$/\1/' abc
これを行う方法はありますか?
\n
、Linuxでは1文字です
回答:
perl -pe 'chomp if eof' filename >filename2
または、ファイルをその場で編集するには:
perl -pi -e 'chomp if eof' filename
[編集者注:-pi -e
はもともとでした-pie
が、いくつかのコメンターによって指摘され、@ hvdによって説明されたように、後者は機能しません。]
これは、私が見たawkウェブサイトで「perl冒涜」と説明されていました。
しかし、テストでは、うまくいきました。
chomp
ます。そして、それはファイルを丸呑みするのに勝ります。
perl -pi -e 'chomp if eof' filename
、一時ファイルを作成する代わりにインプレースでファイルを編集することができます
perl -pie 'chomp if eof' filename
-> Perlスクリプト "chomp if eof"を開けません:そのようなファイルやディレクトリはありません。perl -pi -e 'chomp if eof' filename
- >作品
シェルコマンドの置換によって末尾の改行文字が削除されるという事実を利用できます。
bash、ksh、zshで機能する単純な形式:
printf %s "$(< in.txt)" > out.txt
ポータブル(POSIX準拠)の代替(わずかに効率が悪い):
printf %s "$(cat in.txt)" > out.txt
注意:
in.txt
終了している場合、コマンド置換はそれらすべてを削除します -ありがとう、@ Sparhawk。(末尾の改行以外の空白文字は削除されません。)printf %s
何も改行が出力に追加されていないことを保証します(それは非標準のPOSIX準拠の代替であるecho -n
;参照http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.htmlおよびHTTPSを://unix.stackexchange。 com / a / 65819)他の回答へのガイド:
Perlが利用可能な場合は、受け入れられた答えを探してください。それはシンプルでメモリ効率が良いです(入力ファイル全体を一度に読み取らない)。
それ以外の場合は、ghostdog74のAwk回答を検討してください。これはあいまいですが、メモリ効率も高くなります。より読みやすいと同等(POSIX準拠)は、次のとおりです。
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
ブロックで処理できます。\n
出力レコードの区切り文字(OFS
)を空の文字列ます。(元のファイルを置き換える一時ファイルを作成するのとは対照的に)インプレースで本当に編集する冗長で高速かつ堅牢なソリューションが必要な場合は、jrockwayのPerlスクリプトを検討してください。
これはhead
、GNU coreutilsから実行できます。ファイルの末尾に関連する引数をサポートしています。したがって、最後のバイトを省略するには、以下を使用します。
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
from 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の回答で使用されているように、truncate --size=-1
置換できhead -c-1
、インプレース編集をサポートします。
truncate --size=-1
代わりに使用すると思いhead -c -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
バージョンに従います。これには2つのオフセット(および別のテスト)が必要で、1つだけ使用しました。ただし、のprintf
代わりに使用できますORS
。
head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
ガウク
awk '{q=p;p=$0}NR>1{print q}END{ORS = ""; print p}' file
awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file
これは読みやすいはずです。
awk 'NR>1 {print p} {p=$0} END {printf $0}' file
。
printf
はフォーマット引数です。したがって、入力ファイルにのような形式指定子として解釈できるものがあった場合、%d
エラーが発生します。修正はそれを次のように変更することですprintf "%s" $0
coreutilsからのGNU echoを必要とする単一行ファイルの非常に単純な方法:
/bin/echo -n $(cat $file)
\n
存在する場合、これには問題があります。新しい行に変換されます。
$(...)
引用されている複数行のファイルでも機能するようです
/bin/echo -n "$(cat infile)"
また、echo
os / shellバージョン/ distros全体の最大長またはシェルがどうなるかわかりません(私はこれをググっているだけで、うさぎの穴でした)。小さなファイル以外の場合に実際に移植可能(またはパフォーマンス)であるかどうかはわかりませんが、小さなファイルの場合は素晴らしいです。
正しく実行したい場合は、次のようなものが必要です。
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
は、ファイルの最後まで既に移動していることを意味します。次に、でファイルの最後の数値位置を取得します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)
PS「Perlゴルフ」の精神で、ここに私の最短のPythonソリューションがあります。ファイル全体を標準入力からメモリに取り込み、改行をすべて取り除き、結果を標準出力に書き込みます。Perlほど簡潔ではありません。このような少しトリッキーで速いもののためにPerlを倒すことはできません。
への呼び出しから「\ n」を削除します .rstrip()
と、複数の空白行を含め、ファイルの末尾からすべての空白が削除されます。
これを「slurp_and_chomp.py」に入れて、を実行しpython slurp_and_chomp.py < inputfile > outputfile
ます。
import sys
sys.stdout.write(sys.stdin.read().rstrip("\n"))
高速な解決策は、gnuユーティリティを使用することですtruncate
。
[ -z $(tail -c1 file) ] && truncate -s-1 file
ファイルに末尾の新しい行がある場合、テストは真になります。
削除は非常に高速で、本当に適切です。新しいファイルは必要なく、検索も最後から1バイト(tail -c1
)だけ読み取っています。
[ -z $(tail -c1 filename) ] && truncate -s -1 filename
(つまり、他のコメントへの応答として、truncate
コマンドはstdinでは機能しません。ファイル名が必要です)
$ perl -e 'ローカル$ /; $ _ = <>; s / \ n $ //; 印刷 'a-text-file.txt
sedの任意の文字(改行を含む)にも一致するを参照してください。
tr -d '\n'
perl -pi -e 's/\n$// if(eof)' your_file
g
周りの括弧はeof
:perl -pi -e 's/\n$// if eof' your_file
。
Unixファイルタイプを想定していて、最後の改行だけが必要な場合。
sed -e '${/^$/d}'
複数の改行では機能しません...
* 最後の行が空白行である場合にのみ機能します。
sed
非空白最後の行のためにも機能するソリューションは:stackoverflow.com/a/52047796
さらに別の答え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.
echo -en 'a\nb\n' | sed '${/^$/d}'
何も削除されません。echo -en 'a\nb\n\n' | sed '${/^$/d}'
最後の行全体が空白なので、削除されます。
これは、ファイルからの読み取りまたはファイルへの出力ではなく、パイプ/リダイレクトで作業する必要がある場合に適したソリューションです。これは単一または複数の行で機能します。後続の改行があるかどうかに関係なく機能します。
# 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バッファーの制限のため)