Bir dizindeki tüm dosyaların son satırı nasıl kaldırılır?


17

Bir dizinde çok sayıda metin dosyası var ve dizindeki her dosyanın son satırını kaldırmak istiyorum.

Nasıl yapabilirim?


6
Ne denedin? unix.stackexchange.com/help/how-to-ask : "Araştırmanızı paylaşmak herkese yardımcı olur. Bize ne bulduğunuzu ve neden ihtiyaçlarınızı karşılamadığını söyleyin. Bu, kendinize yardım etmeye zaman ayırdığınızı gösterir , bizi bariz cevapları yinelemekten kurtarıyor ve her şeyden önce daha spesifik ve alakalı bir cevap almanıza yardımcı oluyor! "
Patrick

Neden birileri düşüncesi yanlışlıkla / etc :) yaltaklanmak indüksiyon çok özel kalitesine sahip olduğunu uygulayarak yok
rackandboneman

Yanıtlar:


4

Erişim vimizniniz varsa şunları kullanabilirsiniz:

for file in ./*
do
  if [ -f "${file}" ]
  then
    vim -c '$d' -c "wq" "${file}"
  fi
done

16

GNU'nuz varsa bu güzel oneliner'ı kullanabilirsiniz sed.

 sed -i '$ d' ./*

Geçerli dizindeki gizli olmayan her dosyanın son satırını kaldıracaktır. -iGNU anahtarı sed, yerinde çalışmak anlamına gelir ve son satırı silmek için '$ d'komut verir sed( $son ve danlamı sil anlamına gelir).


3
Klasör normal bir dosya dışında bir şey içeriyorsa, bu hatalar atar (ve hiçbir şey yapmaz), örneğin başka bir klasör ...
Najib Idrissi

1
Sen kullandığınız @StefanR -ibu tartışmaya açıktır, bu yüzden bir GNUism olan ama bazı eski sürümleri işaret etmemesi halinde benim eski sakal ayakta kaybedecek sedsen arasında herhangi boşluk koymak için izin vermez $ve d(veya, genel olarak, desen ve komut arasında).
zwol

1
@zwol Yazdığım gibi, bu bir uyarı değil , bir hata ile sonuçlanacak ve sed bu dosyaya ulaştığında pes edecek (en azından sahip olduğum sed sürümü ile). Sonraki dosyalar işlenmeyecek. Hata mesajlarını atmak korkunç bir fikir olurdu, çünkü bunun olduğunu bile bilmiyordunuz! *(.)Zsh ile normal dosyalar için glob kullanabilirsiniz , diğer kabuklar hakkında bilmiyorum.
Najib Idrissi

@NajibIdrissi Hmm, haklısın. Bu beni şaşırtıyor; Ben dizin hakkında şikayet ama daha sonra komut satırındaki bir sonraki dosyaya gitmek umuyordum. Aslında, bunu bir hata olarak rapor edeceğimi düşünüyorum.
zwol

@ don_crissti GNU sed v4.3 de var ... Sana ne diyeceğimi bilmiyorum, sadece tekrar test ettim. gist.github.com/nidrissi/66fad6be334234f5dbb41c539d84d61e
Najib Idrissi

11

Dizin, normal bir dosyadan başka bir şey veya dosya adında boşluk / yeni satır içeren bir dosya içeriyorsa, diğer yanıtların tümü de sorun yaşar. İşte ne olursa olsun çalışan bir şey:

find "$dir" -type f -exec sed -i '$d' '{}' '+'
  • find "$dir" -type f: dizindeki dosyaları bul $dir
    • -type f bunlar normal dosyalar;
    • -exec bulunan her dosyada komutu çalıştır
    • sed -i: dosyaları yerinde düzenleme;
    • '$d': dson ( $) satırı sil ( ) .
    • '+': bulmaya argümanlar eklemeye devam etmesini söyler sed(@zwol sayesinde her dosya için komutu ayrı ayrı çalıştırmaktan biraz daha verimli).

Eğer alt dizinleri içine inerek istemiyorsanız, o zaman argüman ekleyebilir -maxdepth 1için find.


1
Hmm, ama diğer cevapların aksine bu alt dizinlere iniyor . (Ayrıca, mevcut sürümleri findile daha verimli bir şekilde yazılır find $dir -type f -exec sed -i '$d' '{}' '+'.)
zwol

@zwol Teşekkürler, cevaba ekledim.
Najib Idrissi

-print0tam komutta yok, neden açıklamaya koymalıyım?
Ruslan

1
Ayrıca, -depth 0işe yaramaz (findutils 4.4.2), bunun yerine olması gerekir -maxdepth 1.
Ruslan

@Ruslan xargs kullandığım ama sonra hatırladığım ilk versiyonum vardı -exec.
Najib Idrissi

9

GNU kullanma sed -i '$d' , tam dosyayı okumak ve son satır olmadan bir kopyasını oluşturmak anlamına gelirken, dosyayı yerinde kısaltmak çok daha verimli olacaktır (en azından büyük dosyalar için).

GNU ile truncateşunları yapabilirsiniz:

for file in ./*; do
  [ -f "$file" ] &&
    length=$(tail -n 1 "$file" | wc -c) &&
    [ "$length" -gt 0 ] &&
    truncate -s "-$length" "$file"
done

Dosyalar nispeten küçükse, dosya başına birkaç komut çalıştırdığı için bu muhtemelen daha az verimli olacaktır.

Son satırsonu karakterinden sonra (son satırdan sonra) veya başka bir deyişle sınırlandırılmamış bir son satır varsa , tailuygulamaya bağlı olarak fazladan bayt içeren dosyalar için , tail -n 1yalnızca bu fazladan baytları (GNU gibi tail) döndüreceğini unutmayın. veya son (uygun şekilde sınırlandırılmış) satır ve bu fazladan bayt.


Eğer bir ihtiyacın var |wc -ciçinde tailçağrı? (veya a ${#length})
Jeff Schaller

@JeffSchaller. Hata. wc -c gerçekten amaçlanmıştı. ${#length}karakterleri sayar, bayt değil $(...), kuyruk satırsonu karakterini kaldırır, böylece ${#...}tüm karakterler tek bayt olsa bile birer birer kapalı olur.
Stéphane Chazelas

6

Daha taşınabilir bir yaklaşım:

for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done

Ben ... Bu herhangi bir açıklama ihtiyacı olduğunu bu durumda belki hariç değil daynıdır $dçünkü edvarsayılan seçer son satırı ile.
Bu özyinelemeli olarak arama yapmaz ve gizli dosyaları (dotfiles olarak da bilinir) işlemez.
Bunları da düzenlemek istiyorsanız, bkz. Bir dizindeki gizli dosyalarla nasıl eşleştirilir *


Güzel! Bunu değiştirirseniz [[]], []tam olarak POSIX uyumlu olacaktır. ( [[ ... ]]Bir Bashism içindir.)
Joker

@Wildcard - teşekkürler, değişti ( [[bir bashizm olmasa da )
don_crissti

POSIX olmayan bir şey söylemeliyim. :)
Wildcard

3

Nokta dosyaları da dahil olmak üzere geçerli dizinde tekrarlayan tüm dosyalar için POSIX uyumlu tek astar:

find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +

İçin .txtdosyaları sadece olmayan yinelemeli:

find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +

Ayrıca bakınız:

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.