Bir dizinde çok sayıda metin dosyası var ve dizindeki her dosyanın son satırını kaldırmak istiyorum.
Nasıl yapabilirim?
Bir dizinde çok sayıda metin dosyası var ve dizindeki her dosyanın son satırını kaldırmak istiyorum.
Nasıl yapabilirim?
Yanıtlar:
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. -i
GNU anahtarı sed
, yerinde çalışmak anlamına gelir ve son satırı silmek için '$ d'
komut verir sed
( $
son ve d
anlamı sil anlamına gelir).
-i
bu 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 sed
sen arasında herhangi boşluk koymak için izin vermez $
ve d
(veya, genel olarak, desen ve komut arasında).
*(.)
Zsh ile normal dosyalar için glob kullanabilirsiniz , diğer kabuklar hakkında bilmiyorum.
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ırsed -i
: dosyaları yerinde düzenleme;'$d'
: d
son ( $
) 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 1
için find
.
find
ile daha verimli bir şekilde yazılır find $dir -type f -exec sed -i '$d' '{}' '+'
.)
-print0
tam komutta yok, neden açıklamaya koymalıyım?
-depth 0
işe yaramaz (findutils 4.4.2), bunun yerine olması gerekir -maxdepth 1
.
-exec
.
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 , tail
uygulamaya bağlı olarak fazladan bayt içeren dosyalar için , tail -n 1
yalnı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.
|wc -c
içinde tail
çağrı? (veya a ${#length}
)
${#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.
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 d
aynıdır $d
çünkü ed
varsayı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 *
[[]]
, []
tam olarak POSIX uyumlu olacaktır. ( [[ ... ]]
Bir Bashism içindir.)
[[
bir bashizm olmasa da )
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 .txt
dosyaları 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: