Saya memiliki banyak file teks dalam direktori, dan saya ingin menghapus baris terakhir dari setiap file dalam direktori.
Bagaimana saya bisa melakukannya?
Saya memiliki banyak file teks dalam direktori, dan saya ingin menghapus baris terakhir dari setiap file dalam direktori.
Bagaimana saya bisa melakukannya?
Jawaban:
Anda dapat menggunakan oneliner yang bagus ini jika Anda memiliki GNU sed.
sed -i '$ d' ./*
Ini akan menghapus baris terakhir dari setiap file yang tidak disembunyikan di direktori saat ini. Beralih -iuntuk GNU sedberarti beroperasi di tempat dan '$ d'memerintahkan seduntuk menghapus baris terakhir ( $artinya terakhir dan dberarti menghapus).
-iyang merupakan GNUism, jadi ini bisa diperdebatkan, tapi saya akan kehilangan janggut lama saya jika saya gagal menunjukkan bahwa beberapa versi yang lebih lama sedtidak memungkinkan Anda untuk meletakkan spasi kosong apa pun di antara $dan d(atau, secara umum, antara pola dan perintah).
*(.)untuk glob untuk file biasa, saya tidak tahu tentang shell lainnya.
Jawaban lain semua memiliki masalah jika direktori berisi sesuatu selain file biasa, atau file dengan spasi / baris baru dalam nama file. Berikut ini sesuatu yang berfungsi:
find "$dir" -type f -exec sed -i '$d' '{}' '+'
find "$dir" -type f: cari file di direktori $dir
-type f yang merupakan file biasa;-exec jalankan perintah pada setiap file yang ditemukansed -i: mengedit file di tempat;'$d': delete ( d) baris terakhir ( $).'+': memberitahu find untuk terus menambahkan argumen sed(sedikit lebih efisien daripada menjalankan perintah untuk setiap file secara terpisah, terima kasih kepada @zwol).Jika Anda tidak ingin turun ke subdirektori, maka Anda dapat menambahkan argumen -maxdepth 1ke find.
findini, ini ditulis dengan lebih efisien find $dir -type f -exec sed -i '$d' '{}' '+'.)
-print0tidak hadir dalam perintah penuh, mengapa memasukkannya ke dalam penjelasan?
-depth 0tidak berfungsi (findutils 4.4.2), mestinya sebaliknya -maxdepth 1.
-exec.
Menggunakan GNU sed -i '$d'berarti membaca file lengkap dan membuat salinannya tanpa baris terakhir, sementara itu akan jauh lebih efisien untuk hanya memotong file di tempat (setidaknya untuk file besar).
Dengan GNU truncate, Anda dapat melakukan:
for file in ./*; do
[ -f "$file" ] &&
length=$(tail -n 1 "$file" | wc -c) &&
[ "$length" -gt 0 ] &&
truncate -s "-$length" "$file"
done
Jika file relatif kecil, itu mungkin akan kurang efisien karena menjalankan beberapa perintah per file.
Perhatikan bahwa untuk file yang berisi byte tambahan setelah karakter baris baru terakhir (setelah baris terakhir) atau dengan kata lain jika mereka memiliki baris terakhir yang tidak dibatasi , maka tergantung pada tailimplementasinya, tail -n 1akan mengembalikan hanya byte tambahan tersebut (seperti GNU tail), atau baris terakhir (dibatasi dengan benar) dan byte tambahan itu.
|wc -cdi tailpanggilan? (atau a ${#length})
${#length}tidak akan berfungsi karena menghitung karakter, bukan byte dan $(...)akan menghapus karakter baris baru tailing sehingga ${#...}akan dimatikan oleh satu bahkan jika semua karakter single-byte.
Pendekatan yang lebih portabel:
for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done
Saya tidak berpikir ini perlu penjelasan apa pun ... kecuali mungkin dalam kasus dini sama $dkarena edsecara default memilih baris terakhir.
Ini tidak akan mencari secara rekursif dan tidak akan memproses file tersembunyi (alias dotfiles).
Jika Anda ingin mengeditnya juga lihat Cara mencocokkan * dengan file tersembunyi di dalam direktori
[[]]ke []maka akan sepenuhnya POSIX compliant. ( [[ ... ]]is a Bashism.)
[[bukan bashism )
Satu-liner yang sesuai dengan POSIX untuk semua file secara rekursif dimulai pada direktori saat ini, termasuk dot-file:
find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
Hanya untuk .txtfile, non-rekursif:
find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
Lihat juga: