Sonunda boş satır olmayan dosyalar nasıl bulunur?


9

Sonunda yeni satırları olabilir veya olmayabilir geçerli dizinin alt dizinleri dosyaları var; sonunda satırsonu olmayan dosyaları nasıl bulabilirim?

Bunu denedim:

find . -name '*.styl' | while read file; do
    awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done

ama işe yaramıyor. awk 'END{print}' $filesatırı boş yeni bir satırdan önce yazdırır tail -n 1 $file.


@don_crissti Sonunda boş satır olmayan dosyalara ihtiyacım var.
jcubic

2
Bu dosyaları bulmanızın nedenini sorabilir miyim? Sanırım unix'teki Metin dosyalarının bir satırsonu ile sonlandırılması gerekiyor (vi, örneğin kaydettiğinizde "neredeyse sessizce" bir tane ekleyecek) ve birkaç (metin odaklı) komutun bir satırsonu tarafından sonlandırılmazsa son satır (wc, iirc .... ama diğerleri var). Ve bu yardımcı olabilir
Olivier Dulac

awk 'END{print}' $file : Bu, $ dosyasının içeriğini tamamen yok sayar ve "$ file" içindeki tüm dosyaları ayrıştırmayı bitirdikten sonra bir satırsonu ekler. Awk komutunun printf '\n'yazdığı tek şey olduğu gibi değiştirilebilir: ($ dosyasının herhangi bir mentino'su olmadan) ve aynı şeyi yapın. Sanırım bu hedeflediğiniz değil DEĞİL (yani: dosyanın son satırını yazdırmak?)
Olivier Dulac

@ don_crissti: Bir dosyanın son karakteri yeni satır değilse, bu dosya bir unix TEXT dosyası olarak sıkıştırılmaz. bkz . unix.stackexchange.com/a/263919/27616 . birçok metin komutunun (örneğin wc), bir satırsonu tarafından sonlandırılmazsa son satırını görmezden geldiğini unutmayın
Olivier Dulac

1
@OlivierDulac: gawk cFreeBSD'yi yazdırır ve uygular , ancak uygulamaya bağlı olarak belgelendiğini fark etmemiştim: gnu.org/software/gawk/manual/… . Yani yok ama her zaman olur.
dave_thompson_085

Yanıtlar:


14

Açıklığa kavuşturmak gerekirse, LF (aka \nveya satırsonu) karakteri satır sınırlayıcıdır , satır ayırıcı değildir. Bir satır, yeni satır karakteri ile sonlandırılmadığı sürece bitmez. Yalnızca içeren a\nbbir dosya, son satırdan sonra karakterler içerdiğinden geçerli bir metin dosyası değil. Yalnızca içeren bir dosya için aynıdır a. a\nİçeren bir dosya boş olmayan bir satır içeriyor.

Dolayısıyla, en az bir boş satırla biten bir dosya iki yeni satır karakteri ile biter veya tek bir yeni satır karakteri içerir.

Eğer:

 tail -c 2 file | od -An -vtc

Çıktılar \nveya \n \ndosya en az bir boş satır içeriyor. Hiçbir şey çıktısı almazsa, bu boş bir dosyadır, çıktısı çıkarsa <anything-but-\0> \nboş olmayan bir satırla biter. Başka bir şey, bir metin dosyası değil.

Şimdi, boş bir satırla biten dosyaları bulmak için bunu kullanmak yeterlidir (özellikle büyük dosyalar için), dosyaların yalnızca son iki baytını okur, ancak önce çıktı, programlı olarak kolayca ayrıştırılamaz. bir uygulamadan diğerine tutarlı değildir ve her dosya için odbir tailve bir tane çalıştırmamız gerekir od.

find . -type f -size +0 -exec gawk '
  ENDFILE{if ($0 == "") print FILENAME}' {} +

(boş bir satırla biten dosyaları bulmak için) mümkün olduğunca az komut çalıştırır, ancak tüm dosyaların tam içeriğini okumak anlamına gelir.

İdeal olarak, bir dosyanın sonunu tek başına okuyabilen bir kabuğa ihtiyacınız olacaktır.

İle zsh:

zmodload zsh/system
for f (**/*(D.L+0)) {
  {
    sysseek -w end -2
    sysread
    [[ $REPLY = $'\n' || $REPLY = $'\n\n' ]] && print -r -- $f
  } < $f
}

bir yol bazı dosya (s) eğer olan metin dosyaları bilmek için bu cevabım yöntemi kullanmak: are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }. Kullanım şekli:if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
Olivier Dulac

6

İle gnu sedve bir kabuk gibi zsh(veya bashile shopt -s globstar):

sed -ns '${/./F}' ./**/*.styl

bu, her dosyanın son satırının boş olup olmadığını kontrol eder, eğer öyleyse dosya adını yazdırır.
Eğer tersini istiyorsanız, sadece değiştirin (son satır boşsa dosya adları yazdırmak) /./ile/^$/


1
Daha -sönce hiç eylemde bulunmadım. Teşekkürler GNU!
glenn jackman

Not: F seçeneği sed 4.2.2 sürümünden (22 Aralık 2012) mevcuttur
Isaac

3

Son satırı boş olan doğru şekilde sonlandırılmış bir metin dosyası ikiyle biter \n.

Sonra tail -c2bunun eşit olmasını bekliyoruz $'\n\n'.

Ne yazık ki komut genişletmeleri sondaki yeni satırları kaldırır. Biraz ince ayar yapmamız gerekecek.

f=filename
nl='
'
t=$(tail -c2 $f; printf x)  # capture the last two characters.
r="${nl}${nl}$"                 # regex for: "ends in two newlines".
[[ ${t%x} =~ $r ]] &&  echo "file $f ends in an empty line"

Hatta hangi dosyaların yeni bir satır içermediğini kontrol etmek için biraz genişletebiliriz:

nl='
'
nl=$'\n'
find . -type f -name '*.styl' | while read f; do
    t=$(tail -c2 $f; printf x); r1="${nl}$"; r2="${nl}${r1}"
    [[ ${t%x} =~ $r1 ]] || echo "file $f is missing a trailing newline"
    [[ ${t%x} =~ $r2 ]] && echo "$f"
done

Yeni satırın $'\r\ngerektiğinde böyle bir şeye değiştirilebileceğini unutmayın .
Bu durumda, aynı zamanda değiştirmek tail -c2için tail -c4.


0
for file in *; do
    # Check if the file is readable to avoid clutter
    if cat "./$file" 2&>1 /dev/null; then
        # Compare the last character with a single newline character.
        if [ -n "$(tail -c 1 -- "./$file")" ]; then
            echo "$file"
        fi
        # Also report empty files.
        if [ $(wc -c  < "./$file") -eq 0 ]; then
            echo "$file"
        fi
    fi
done

1
bu boş dosyalarla çalışmaz ama bununla yaşayabilirim.
jcubic

Dize karşılaştırması beklediğim gibi çalışmıyor gibi görünüyor çünkü bazı hatalar olabilir. Boş dosyalar için bir kontrol ekledim.
Oskar Skog

Ah, yeni satır karakterlerini yok sayar.
Oskar Skog

Daha okunabilir cat $file 2>&1 /dev/nullolanı veya bu yalnızca Bash ise düşünün cat $file &> /dev/null.
kedi

1
Ayrıca, $filekullanıldığı her yerde alıntı yapmayı düşünün - ve lütfen, $(commands ...)bunun yerine kullanın `backticks`...
cat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.