Versiyon kontrol sistemlerini kullanarak, fark söylediğinde gürültüden rahatsız oluyorum No newline at end of file
.
Ben de merak ediyordum: Bu mesajlardan kurtulmak için bir dosyanın sonuna nasıl yeni bir satır eklenir?
Versiyon kontrol sistemlerini kullanarak, fark söylediğinde gürültüden rahatsız oluyorum No newline at end of file
.
Ben de merak ediyordum: Bu mesajlardan kurtulmak için bir dosyanın sonuna nasıl yeni bir satır eklenir?
Yanıtlar:
Bir projeyi tekrar tekrar sterilize etmek için bu oneliner'ı kullanıyorum:
git ls-files -z | while IFS= read -rd '' f; do tail -c1 < "$f" | read -r _ || echo >> "$f"; done
Açıklama:
git ls-files -z
Havuzdaki dosyaları listeler. İşlemi belirli dosyalar / dizinlerle sınırlamak istiyorsanız, bazı durumlarda yararlı olabilecek ek bir parametre olarak isteğe bağlı bir model alır. Alternatif olarak, find -print0 ...
etkilenen dosyaları listelemek için veya benzer programlar kullanabilirsiniz - yalnızca NUL
sınırlı girdiler verdiğinden emin olun .
while IFS= read -rd '' f; do ... done
beyaz boşluk ve / veya yeni satırlar içeren dosya adlarını güvenle işleyerek girişleri yineler.
tail -c1 < "$f"
bir dosyadan son karakteri okur.
read -r _
Sonunda yeni bir satır eksikse, sıfır olmayan bir durumla çıkar.
|| echo >> "$f"
önceki komutun çıkış durumu sıfır değilse, dosyaya yeni bir satır ekler.
find -name \*.java | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
git ls-files
sürüm kontrolünde izlenmeyen dosyaları düzenlemekten sizi kurtaracak bir kalıp da geçirebilirsiniz .
IFS=
Ayırıcıyı serbest bırakmak için eklenen @ StéphaneChazelas , çevresindeki boşluğu korumak için iyidir. Boş sonlandırılmış girişler yalnızca adlarında yeni bir satır bulunan, çok uzak alınmış gibi görünen, ancak genel durumu ele almanın daha doğru bir yolu olan dosyalarınız veya dizinleriniz varsa alakalı olur. Küçük bir uyarı olarak: POSIX sh'de bu -d
seçenek read
mevcut değil.
tail -n1 < "$f"
, dosya adlarıyla ilgili sorunlardan kaçınmak için kullanımımı da inceleyin -
( tail -n1 -- "$f"
çağrılan dosya için çalışmaz -
). Cevabın şimdi zsh / bash'a özgü olduğunu açıklığa kavuşturmak isteyebilirsiniz.
Buyrun :
sed -i -e '$a\' file
Ve alternatif olarak OS X için sed
:
sed -i '' -e '$a\' file
Bu \n
, dosyanın sonuna sadece yeni bir satırla bitmediyse eklenir . Dolayısıyla, iki kez çalıştırırsanız, başka bir yeni satır eklemeyecektir:
$ cd "$(mktemp -d)"
$ printf foo > test.txt
$ sed -e '$a\' test.txt > test-with-eol.txt
$ diff test*
1c1
< foo
\ No newline at end of file
---
> foo
$ echo $?
1
$ sed -e '$a\' test-with-eol.txt > test-still-with-one-eol.txt
$ diff test-with-eol.txt test-still-with-one-eol.txt
$ echo $?
0
man sed
: $ Match the last line.
Ama belki de sadece kazayla çalışır. Çözümünüz de işe yarıyor.
$
. Bir regex'in içinde olduğu gibi /<regex>/
, "olağan eşleşmenin sonu" anlamına gelir. Aksi halde bir adres olarak kullanılan sed, özel "dosyadaki son satır" anlamını verir. Kod çalışır çünkü varsayılan olarak sed, zaten orada değilse, çıktısına yeni bir satır ekler. "$ A \" kodu sadece "dosyanın son satırıyla eşleşiyor ve hiçbir şey eklemiyor" diyor. Ancak, dolaylı olarak, sed $
, henüz orada değilse, işlediği her satıra (bu satır gibi ) yeni satırı ekler .
/regex/
, farklı bir anlam verir. FreeBSD broşürleri
Bir göz atın:
$ echo -n foo > foo
$ cat foo
foo$
$ echo "" >> foo
$ cat foo
foo
bu yüzden echo "" >> noeol-file
hile yapmak gerekir. (Ya da bu dosyaları tanımlamak ve düzeltmek için sormak mı istediniz ?)
edit kaldırıldı ""
from echo "" >> foo
(@ yuyichao'nın yorumuna bakın)
edit2""
yine ekledi ( ama @Keith Thompson'ın yorumuna bakın)
""
(en azından Bash için) gerekli değildir ve tail -1 | wc -l
sonunda, yeni bir hat olmadan dosyayı bulmak için kullanılabilir
""
bash için gerekli değil, ancak echo
argümanlar olmadan çağrıldığında hiçbir şey yazamayan uygulamalar gördüm (şu anda bulabileceğim hiçbiri olmasa da). echo "" >> noeol-file
muhtemelen biraz daha sağlamdır. printf "\n" >> noeol-file
daha da öyle.
csh
' echo
herhangi bir argüman geçmediğinde hiçbir şey çıkmadığı bilinen kişidir. Ama biz olmayan Bourne benzeri kabukları desteklemek için gidiyoruz sonra eğer, bunu yapmalıdır echo ''
yerine echo ""
olarak echo ""
çıktıya ediyorum ""<newline>
ile rc
veya es
mesela.
tcsh
, aksine csh
, herhangi bir argüman olmadan çağrıldığında - ayarından bağımsız olarak yeni bir satır yazdırır $echo_style
.
Başka bir çözüm kullanarak ed
. Bu çözüm yalnızca son satırı etkiler ve yalnızca \n
eksikse:
ed -s file <<< w
Esasen dosyayı bir komut dosyası aracılığıyla düzenlemek için açılmakla çalışır, komut dosyası w
dosyayı diske geri yazan tek komuttur. ed(1)
Man sayfasında bulunan bu cümleyi temel alır :
SINIRLAMA (...) Metin (ikili olmayan) bir dosya yeni satır karakteriyle sonlandırılmazsa, sonra ed okuma / yazma üzerine bir tane ekler. İkili bir durumda ed, okuma / yazma üzerine yeni bir satır eklemiyor.
Bir metin dosyasına eksik, son bir yeni satır eklemek için basit, taşınabilir, POSIX uyumlu bir yol:
[ -n "$(tail -c1 file)" ] && echo >> file
Bu yaklaşımın tüm dosyayı okumasına gerek yoktur; sadece EOF'ye başvurabilir ve oradan çalışabilir.
Bu yaklaşım aynı zamanda arkanızdan temp dosyaları oluşturmanıza da gerek duymaz (örn. Sed -i), bu nedenle hardlinks etkilenmez.
echo, yalnızca komut değiştirme sonucu boş olmayan bir dize olduğunda dosyaya yeni bir satır ekler. Bunun yalnızca dosya boş değilse ve son bayt yeni satır olmadığında olabileceğini unutmayın.
Dosyanın son baytı yeni bir satırsa, kuyruk onu döndürür, sonra komut değiştirme onu soyar; sonuç boş bir dizedir. -N testi başarısız olur ve yankı çalışmaz.
Dosya boşsa, komut değiştirme işleminin sonucu da boş bir dizedir ve yeniden yankı çalışmaz. Bu arzu edilir, çünkü boş bir dosya geçersiz bir metin dosyası değildir ve boş bir satır içeren boş olmayan bir metin dosyasına eşdeğer değildir.
yash
dosyasındaki son karakteri (örneğin UTF-8 yerellerde) bir multi-byte karakter veya yerel C ve eğer dosyasındaki son bayt 8 bit kümesi varsa. Diğer kabuklarda (zsh hariç), dosya NUL baytında sona ererse yeni bir satır eklemeyecekti (ancak daha sonra, giriş yeni satır eklendikten sonra bile metin dışı olacağı anlamına gelir).
Ne olursa olsun yeni satır ekleyin:
echo >> filename
Python kullanarak bir tane eklemeden önce yeni bir satır olup olmadığını kontrol etmenin bir yolu:
f=filename; python -c "import sys; sys.exit(open(\"$f\").read().endswith('\n'))" && echo >> $f
echo ""
daha sağlam görünüyor echo -n '\n'
. Ya da kullanabilirsinizprintf '\n'
En hızlı çözüm:
[ -n "$(tail -c1 file)" ] && printf '\n' >>file
Gerçekten hızlı.
Orta büyüklükteki bir dosyada seq 99999999 >file
bu milisaniye sürer.
Diğer çözümler uzun zaman alıyor:
[ -n "$(tail -c1 file)" ] && printf '\n' >>file 0.013 sec
vi -ecwq file 2.544 sec
paste file 1<> file 31.943 sec
ed -s file <<< w 1m 4.422 sec
sed -i -e '$a\' file 3m 20.931 sec
Kül, bash, lksh, mksh, ksh93, attsh ve zsh'de çalışır ancak yash değildir.
Yam için taşınabilir bir çözüme ihtiyacınız varsa (ve yukarıda listelenen tüm diğer mermiler), biraz daha karmaşık olabilir
f=file
if [ "$(tail -c1 "$f"; echo x)" != "$(printf '\nx')" ]
then printf '\n' >>"$f"
fi
Bir dosyanın son baytının yeni bir satır olup olmadığını test etmenin en hızlı yolu, sadece bu son baytı okumaktır. Bu yapılabilir tail -c1 file
. Bununla birlikte, bayt değerinin yeni bir satır olup olmadığını sınamanın basit yolu, bir komut genişletme içindeki izleyen yeni satırın genel olarak kaldırılmasına bağlı olarak (örneğin) dosyadaki son karakter bir UTF olduğunda yash'ta başarısız olur. 8 değer.
Doğru, POSIX uyumlu, tümü (makul), dosyanın son baytının yeni bir satır olup olmadığını bulmak için xxd veya hexdump kullanmak mıdır?
tail -c1 file | xxd -u -p
tail -c1 file | hexdump -v -e '/1 "%02X"'
Ardından, yukarıdaki çıktının karşılaştırılması 0A
sağlam bir test sağlayacaktır.
Boş bir dosyaya yeni bir satır eklemekten kaçınmak faydalıdır. Tabii ki,
son karakterini sağlamada başarısız olan dosya 0A
:
f=file
a=$(tail -c1 "$f" | hexdump -v -e '/1 "%02X"')
[ -s "$f" -a "$a" != "0A" ] && echo >> "$f"
Kısa ve güzel. Bu sadece son baytı okuduğu için çok az zaman alır (EOF'u aramak). Dosyanın büyük olup olmaması önemli değil. Sonra gerekirse yalnızca bir bayt ekleyin.
Geçici dosyaya gerek yoktur, kullanılmaz. Hiçbir sabit bağlantı etkilenmez.
Bu testin iki kez çalıştırılırsa, bu olacak değil başka yeni satır ekleyin.
xxd
ne hexdump
olduğuna dikkat edin. POSIX araç testinde od -An -tx1
bir baytın onaltılık değerini elde etmek gerekir.
Dosyayı en son düzenleyen kullanıcının düzenleyicisini düzeltirseniz daha iyi olursunuz. Dosyayı düzenleyen son kişiyseniz, hangi editörü kullanıyorsunuz, metin arkadaşı tahmin ediyorum ..?
emacs
dosyanın sonuna bir yeni satır eklemeyin.
(setq require-final-newline 'ask)
benim içinde.emacs
Bazı boru hatlarını işlerken hızlıca yeni bir satır eklemek istiyorsanız, şunu kullanın:
outputting_program | { cat ; echo ; }
Aynı zamanda POSIX uyumludur.
Sonra, elbette, onu bir dosyaya yönlendirebilirsiniz.
cat file.csv | tr "\r" "\n" | { cat; echo; } | sed "/^[[:space:]]*$/d" | tail -n +2 | wc -l
Sunulan girişde boş değer yoktur:
paste - <>infile >&0
... her zaman yalnızca bir dolgunun kuyruğuna yeni bir satır eklemek için yeterli olurdu. Ve doğru dosyayı almak için yalnızca bir defa girdi dosyasını okuması gerekir.
paste infile 1<> infile
yerine ihtiyacın olacak .
Soruyu doğrudan cevaplamamasına rağmen, işte yeni satırda bitmeyen dosyaları saptamak için yazdığım ilgili bir komut dosyası. Çok hızlı.
find . -type f | # sort | # sort file names if you like
/usr/bin/perl -lne '
open FH, "<", $_ or do { print " error: $_"; next };
$pos = sysseek FH, 0, 2; # seek to EOF
if (!defined $pos) { print " error: $_"; next }
if ($pos == 0) { print " empty: $_"; next }
$pos = sysseek FH, -1, 1; # seek to last char
if (!defined $pos) { print " error: $_"; next }
$cnt = sysread FH, $c, 1;
if (!$cnt) { print " error: $_"; next }
if ($c eq "\n") { print " EOL: $_"; next }
else { print "no EOL: $_"; next }
'
Perl betiği (isteğe bağlı olarak sıralanmış) dosya adlarının bir listesini stdin'den okur ve her dosya için, dosyanın yeni bir satırda bitip bitmeyeceğini belirlemek için son baytı okur. Çok hızlı çünkü her dosyanın içeriğini okumaktan kaçınıyor. Okuduğu her dosya için bir satır çıktısı alır, "error:" ile bir tür hata oluşursa, "empty:", eğer boş ise (newline ile bitmiyor!), "EOL:" (" satır ") dosya newline ile bitiyorsa ve" no EOL: "ise dosya newline ile bitmiyorsa.
Not: Betik, yeni satırlar içeren dosya adlarını işlemez. Bir GNU veya BSD sistemindeyseniz, olası tüm dosya adlarını, bulmak için -print0, sıralamak için -z ve perl için -0 ekleyerek kullanabilirsiniz:
find . -type f -print0 | sort -z |
/usr/bin/perl -ln0e '
open FH, "<", $_ or do { print " error: $_"; next };
$pos = sysseek FH, 0, 2; # seek to EOF
if (!defined $pos) { print " error: $_"; next }
if ($pos == 0) { print " empty: $_"; next }
$pos = sysseek FH, -1, 1; # seek to last char
if (!defined $pos) { print " error: $_"; next }
$cnt = sysread FH, $c, 1;
if (!$cnt) { print " error: $_"; next }
if ($c eq "\n") { print " EOL: $_"; next }
else { print "no EOL: $_"; next }
'
Elbette, dosya isimlerini çıktıda yeni satırlarla kodlamanın bir yolunu bulmanız gerekiyordu (okuyucu için bir alıştırma olarak bırakıldı).
İstenirse çıktı, biri olmayan dosyalara yeni bir satır eklemek için filtrelenebilir.
echo >> "$filename"
Son satırsonu eksikliği kodlarda hatalara neden olabilir, çünkü bazı kabuk sürümleri ve diğer yardımcı programlar, böyle bir dosyayı okurken eksik olan son satırları doğru şekilde işlemeyecektir.
Deneyimlerime göre, son bir yeni satırın olmayışı, dosyaları düzenlemek için çeşitli Windows yardımcı programlarının kullanılmasından kaynaklanıyor. Vim'in bir dosyayı düzenlerken eksik bir son satırın neden olduğunu görmedim, ancak bu tür dosyalar hakkında rapor yazacaktır.
Son olarak, aşağıdakiler gibi yeni satırda bitmeyen dosyaları yazdırmak için dosya adı girişleri üzerinde döngü yapabilen daha kısa (ancak daha yavaş) komut dosyaları vardır:
/usr/bin/perl -ne 'print "$ARGV\n" if /.\z/' -- FILE1 FILE2 ...
vi
/ vim
/ ex
Editörler otomatik eklemek <EOL>
dosya zaten olmadıkça EOF.
O zaman ikisini de deneyin:
vi -ecwq foo.txt
hangi eşdeğerdir:
ex -cwq foo.txt
Test yapmak:
$ printf foo > foo.txt && wc foo.txt
0 1 3 foo.txt
$ ex -scwq foo.txt && wc foo.txt
1 1 4 foo.txt
Birden fazla dosyayı düzeltmek için , şunları kontrol edin: Birçok dosya için 'Dosyanın sonunda yeni satır yok' düzeltmesi nasıl yapılır? SO'da
Bu neden bu kadar önemli? Dosyalarımızı POSIX uyumlu tutmak için .
Kabul edilen yanıtı geçerli dizindeki tüm dosyalara uygulamak için (artı alt dizinler):
$ find . -type f -exec sed -i -e '$a\' {} \;
Bu Linux (Ubuntu) üzerinde çalışır. OS X'te muhtemelen kullanmanız gerekir -i ''
(denenmemiş).
find .
dosyalar dahil tüm dosyaları listelediğine dikkat edin .git
. Hariç tutulacak:find . -type f -not -path './.git/*' -exec sed -i -e '$a\' {} \;
En azından GNU versiyonlarında, eğer mevcut değilse son bir yeni satır ekleyerek girişini basitçe grep ''
ya daawk 1
kuralsızlaştırır. Dosyayı işlem sırasında kopyalarlar; bu işlem büyük olduğunda zaman alır (ancak kaynak yine de okumak için çok büyük olmamalıdır?) Ve siz istediğiniz bir şey yapmadıkça modtime’yı günceller
mv file old; grep '' <old >file; touch -r old file
(Her ne kadar değiştirmiş olduğunuz için kontrol ettiğiniz bir dosyada tamam da olsa da) ve daha da dikkatli olmadığınız sürece hardlinks, varsayılan olmayan izinleri ve ACL'leri vb. kaybeder.
grep '' file 1<> file
, bu yine de dosyayı okuyup yazacaktır.
Bu AIX ksh’de çalışır:
lastchar=`tail -c 1 *filename*`
if [ `echo "$lastchar" | wc -c` -gt "1" ]
then
echo "/n" >> *filename*
fi
Benim durumumda eğer dosyada yeni satır eksikse, wc
komut bir değer döndürür 2
ve yeni satır yazarız.
Patrick Oscity'nin cevabını eklemek , sadece belirli bir dizine uygulamak istiyorsanız, şunları da kullanabilirsiniz:
find -type f | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
Bunu, yeni satır eklemek istediğiniz dizininizde çalıştırın.
echo $'' >> <FILE_NAME>
Dosyanın sonuna boş bir satır ekler.
echo $'\n\n' >> <FILE_NAME>
Dosyanın sonuna 3 boş satır ekleyecektir.
Dosyanız Windows satır sonları ile sonlandırılıyorsa \r\n
ve Linux'taysanız bu sed
komutu kullanabilirsiniz . Henüz \r\n
orada değilse, yalnızca son satıra eklenir :
sed -i -e '$s/\([^\r]\)$/\1\r\n/'
Açıklama:
-i replace in place
-e script to run
$ matches last line of a file
s substitute
\([^\r]\)$ search the last character in the line which is not a \r
\1\r\n replace it with itself and add \r\n
Son satır zaten bir içeriyorsa \r\n
, arama regexp eşleşmeyecek, bu nedenle hiçbir şey olmayacak.
Gibi bir fix-non-delimited-line
komut dosyası yazabilirsiniz :
#! /bin/zsh -
zmodload zsh/system || exit
ret=0
for file do
if sysopen -rwu0 -- "$file"; then
if sysseek -w end -1; then
read -r x || print -u0
else
syserror -p "Can't seek in $file before the last byte: "
ret=1
fi
else
ret=1
fi
done
exit $ret
Burada verilen çözümlerin bazılarının aksine,
Mesela şu şekilde kullanabilirsiniz:
that-script *.txt
veya:
git ls-files -z | xargs -0 that-script
POSIXly ile, işlevsel olarak eşdeğer bir şeyi yapabilirsiniz
export LC_ALL=C
ret=0
for file do
[ -s "$file" ] || continue
{
c=$(tail -c 1 | od -An -vtc)
case $c in
(*'\n'*) ;;
(*[![:space:]]*) printf '\n' >&0 || ret=$?;;
(*) ret=1;; # tail likely failed
esac
} 0<> "$file" || ret=$? # record failure to open
done