Bagaimana cara menghapus spasi kosong dari semua file secara rekursif?

122

Bagaimana Anda bisa menghapus semua spasi kosong dari keseluruhan proyek? Memulai dari direktori root, dan menghapus spasi kosong dari semua file di semua folder.

Selain itu, saya ingin dapat mengubah file secara langsung, dan tidak hanya mencetak semuanya ke stdout.

iamjwc
sumber
Oh, apakah Anda mencari solusi "portabel", atau yang lebih spesifik untuk OS? OS apa yang Anda gunakan?
Joe Pineda
3
Saya ingin melihat versi ini yang akan bekerja pada OS X Snow Leopard, dan akan mengabaikan folder .git dan .svn.
Trevor Turk

Jawaban:

83

Berikut adalah solusi OS X> = 10.6 Snow Leopard.

Ini Mengabaikan folder .git dan .svn dan isinya. Juga tidak akan meninggalkan file cadangan.

export LC_CTYPE=C
export LANG=C
find . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"
deepwell
sumber
10
Anda dapat membuatnya lebih cepat dengan menggunakan \+alih-alih *di string pengganti - Jika tidak, itu cocok di setiap baris.
l0b0
10
Anda dapat menggunakan [[: blank:]] untuk menghapus tab dan spasi.
Leif Gruenwoldt
21
Di Mountain Lion ini kembali sed: RE error: illegal byte sequenceuntukku.
Bryson
12
Bagi Anda yang mengalami masalah dengan "urutan byte ilegal": Masuk export LANG=Cdan coba lagi
Georg Ledermann
3
Di OS X 10.9 saya juga membutuhkan export LC_CTYPE=C seperti yang ditemukan di sini: stackoverflow.com/questions/19242275/…
kissgyorgy
31

Menggunakan:

find . -type f -print0 | xargs -0 perl -pi.bak -e 's/ +$//'

jika Anda tidak ingin file ".bak" dibuat:

find . -type f -print0 | xargs -0 perl -pi -e 's/ +$//'

sebagai pengguna zsh, Anda dapat menghilangkan panggilan untuk menemukan, dan sebagai gantinya menggunakan:

perl -pi -e 's/ +$//' **/*

Catatan: Untuk mencegah menghancurkan .gitdirektori, coba tambahkan: -not -iwholename '*.git*'.

Detik
sumber
37
Jangan coba ini di git repo, karena dapat merusak penyimpanan internal git.
mgold
11
@mgold Terlambat, grrr; /
kenorb
3
Untuk memperjelas, tidak masalah menjalankan ini di dalam subfolder dari repo git, hanya saja tidak di dalam folder yang berisi repo git sebagai turunan, yaitu tidak di dalam folder yang memiliki .gitdirektori, tidak peduli seberapa dalam bersarangnya.
Illya Moskvin
Menggabungkan jawaban ini dengan @ deepwell's untuk menghindari masalah git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss
1
Mungkin ada cara yang lebih baik, tetapi saya memulihkan dari merusak repo git dengan ini dengan mengkloning repo di folder terpisah dan kemudian melakukan rsync -rv --exclude=.git repo/ repo2/setelah itu perubahan lokal repojuga di (tidak rusak) repo2.
MatrixManAtYrService
29

Dua pendekatan alternatif yang juga bekerja dengan baris baru DOS (CR / LF) dan melakukan pekerjaan yang cukup baik dalam menghindari file biner :

Solusi umum yang memeriksa bahwa tipe MIME dimulai dengan text/:

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i 's/[ \t]\+\(\r\?\)$/\1/' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

Solusi khusus repositori Git oleh Mat yang menggunakan-Iopsigit grepuntuk melewati file yang dianggap Git sebagai biner:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'
l0b0
sumber
3
Jadi saya sangat suka solusi git ini. Ini harus benar-benar di atas. Saya tidak ingin menyimpan pengembalian kereta. Tapi saya lebih suka ini daripada yang saya gabungkan pada tahun 2010.
odinho - Velmont
Git saya mengeluh bahwa ekspresi -e kosong, tetapi berfungsi dengan baik menggunakan -e '. *'
muirbot
@okor Di GNU sedopsi sufiks untuk -iadalah opsional , tetapi di BSDsed tidak. Sebenarnya tidak perlu di sini, jadi saya akan menghapusnya saja.
l0b0
24

Di Bash:

find dir -type f -exec sed -i 's/ *$//' '{}' ';'

Catatan: Jika Anda menggunakan .gitrepositori, coba tambahkan: -not -iwholename '.git'.

Adam Rosenfield
sumber
Ini menghasilkan kesalahan seperti ini untuk setiap file yang ditemukan. sed: 1: "dir / file.txt": perintah a mengharapkan \ diikuti oleh teks
iamjwc
Mengganti ';' dengan \; harus bekerja. (Juga kutipan sekitar {} tidak terlalu dibutuhkan).
agnul
4
Untuk menghapus semua spasi, bukan hanya spasi, Anda harus mengganti karakter spasi dengan [: spasi:] dalam ekspresi reguler sed Anda.
WMR
Catatan tambahan: Ini hanya bekerja dengan versi sed> = 4, versi yang lebih kecil tidak mendukung pengeditan tempat.
WMR
1
Ini mematahkan semangat saya :(
CrabMan
14

Ini bekerja untuk saya di OSX 10.5 Leopard, yang tidak menggunakan GNU sed atau xargs.

find dir -type f -print0 | xargs -0 sed -i.bak -E "s/[[:space:]]*$//"

Berhati-hatilah dengan ini jika Anda memiliki file yang perlu dikecualikan (saya lakukan)!

Anda dapat menggunakan -prune untuk mengabaikan direktori atau file tertentu. Untuk file Python dalam repositori git, Anda dapat menggunakan sesuatu seperti:

find dir -not -path '.git' -iname '*.py'
pojo
sumber
Adakah kemungkinan Anda bisa mengklarifikasi ini? Saya ingin perintah yang akan menghapus spasi kosong dari semua file dalam direktori secara rekursif, sambil mengabaikan direktori ".git". Saya tidak bisa mengikuti teladan Anda ...
Trevor Turk
Jika Anda menggunakan tcsh, Anda harus mengubah tanda kutip ganda menjadi tanda kutip tunggal. Jika tidak, Anda akan mendapatkan "Nama variabel ilegal". kesalahan.
Brandon Fosdick
GNU sed serupa tetapi Anda melakukan -i.bak atau --in-place = .bak, berakhir dengan perintah lengkap find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Ganti dirdengan direktori yang dipermasalahkan sebagai tingkat teratas tempat perulangan.
David Gardner
sed -i .bak? Bukankah seharusnya sed -i.bak(tanpa spasi)?
Ondra Žižka
9

Ack dibuat untuk tugas semacam ini.

Ia bekerja seperti grep, tetapi tahu untuk tidak turun ke tempat-tempat seperti .svn, .git, .cvs, dll.

ack --print0 -l '[ \t]+$' | xargs -0 -n1 perl -pi -e 's/[ \t]+$//'

Jauh lebih mudah daripada melompati lingkaran dengan find / grep.

Ack tersedia melalui sebagian besar pengelola paket (sebagai ack atau ack-grep ).

Ini hanya program Perl, jadi ini juga tersedia dalam versi file tunggal yang dapat Anda unduh dan jalankan. Lihat: Ack Install

jbbuckley.dll
sumber
acksangat bagus. Telah menggunakannya selama beberapa tahun, dan tersedia di hampir semua repo paket untuk kebanyakan distro.
Felipe Alvarez
8

ex

Coba gunakan Ex editor (bagian dari Vim):

$ ex +'bufdo!%s/\s\+$//e' -cxa **/*.*

Catatan: Untuk rekursi (bash4 & zsh), kami menggunakan opsi globbing baru ( **/*.*). Aktifkan oleh shopt -s globstar.

Anda dapat menambahkan fungsi berikut ke dalam Anda .bash_profile:

# Strip trailing whitespaces.
# Usage: trim *.*
# See: https://stackoverflow.com/q/10711051/55075
trim() {
  ex +'bufdo!%s/\s\+$//e' -cxa $*
}

sed

Untuk menggunakan sed, periksa: Bagaimana cara menghapus spasi putih tertinggal dengan sed?

find

Temukan skrip berikut (misalnya remove_trail_spaces.sh) untuk menghapus spasi kosong dari file:

#!/bin/sh
# Script to remove trailing whitespace of all files recursively
# See: /programming/149057/how-to-remove-trailing-whitespace-of-all-files-recursively

case "$OSTYPE" in
  darwin*) # OSX 10.5 Leopard, which does not use GNU sed or xargs.
    find . -type f -not -iwholename '*.git*' -print0  | xargs -0 sed -i .bak -E "s/[[:space:]]*$//"
    find . -type f -name \*.bak -print0 | xargs -0 rm -v
    ;;
  *)
    find . -type f -not -iwholename '*.git*' -print0 | xargs -0 perl -pi -e 's/ +$//'
esac

Jalankan skrip ini dari direktori yang ingin Anda pindai. Di OSX pada akhirnya, itu akan menghapus semua file yang diakhiri dengan .bak.

Atau hanya:

find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;

yang direkomendasikan oleh Spring Framework Code Style .

kenorb
sumber
find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;hanya menghapus satu spasi tambahan, bukan semua.
Karl Richter
6

Saya akhirnya tidak menggunakan temukan dan tidak membuat file cadangan.

sed -i '' 's/[[:space:]]*$//g' **/*.*

Bergantung pada kedalaman pohon file, ini (versi yang lebih pendek) mungkin cukup untuk kebutuhan Anda.

CATATAN ini juga membutuhkan file biner, misalnya.

Jesper Rønn-Jensen
sumber
Untuk file tertentu: temukan. -nama '* .rb' | xargs -I {} sed -i '' 's / [[: space:]] * $ // g' {}
Gautam Rege
Anda tidak memerlukan parameter '' untuk sed; atau saya mungkin melewatkan sesuatu. Saya mencobanya pada semua file dalam direktori tertentu, seperti ini: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea
6

Alih-alih mengecualikan file, berikut adalah variasi dari daftar putih di atas yang secara eksplisit mencantumkan file, berdasarkan ekstensi file, yang ingin Anda hapus, silakan bumbui sesuai selera:

find . \( -name *.rb -or -name *.html -or -name *.js -or -name *.coffee -or \
-name *.css -or -name *.scss -or -name *.erb -or -name *.yml -or -name *.ru \) \
-print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"
ChicagoBob
sumber
Agar ini berhasil bagi saya, saya perlu menambahkan kutipan:-name "*.rb*"
haroldcarr
5

Saya akhirnya menjalankan ini, yang merupakan campuran antara versi pojo dan adams.

Ini akan membersihkan kedua spasi kosong, dan juga bentuk lain dari spasi kosong, carriage return:

find . -not \( -name .svn -prune -o -name .git -prune \) -type f \
  -exec sed -i 's/[:space:]+$//' \{} \;  \
  -exec sed -i 's/\r\n$/\n/' \{} \;

Itu tidak akan menyentuh folder .git jika ada.

Edit : Membuatnya sedikit lebih aman setelah komentar, tidak mengizinkan untuk mengambil file dengan ".git" atau ".svn" di dalamnya. Namun berhati-hatilah, ini akan menyentuh file biner jika Anda punya. Gunakan -iname "*.py" -or -iname "*.php"setelah -type fjika Anda hanya ingin menyentuh misalnya file .py dan .php.

Pembaruan 2 : Sekarang mengganti semua jenis spasi di akhir baris (yang juga berarti tab)

odinho - Velmont
sumber
4
Saya tidak tahu apa yang sedang terjadi, tapi ini benar-benar merusak repo git saya dan mengacaukan gambar saya. ORANG, LEBIH HATI-HATI DARIPADA AKU!
mattalxndr
Ya, itu akan merusak file biner. Namun, itu seharusnya tidak menyentuh repo git Anda sama sekali, karena itu melewatkan apa pun yang ada di dalam folder .git. Tapi mungkin hanya jika Anda berada di folder yang sama.
odinho
4

Ini bekerja dengan baik .. tambahkan / hapus - termasuk untuk jenis file tertentu:

egrep -rl ' $' --include *.c *  | xargs sed -i 's/\s\+$//g'
Berikan Murphy
sumber
4

Rubi:

irb
Dir['lib/**/*.rb'].each{|f| x = File.read(f); File.write(f, x.gsub(/[ \t]+$/,"")) }
lebih kotor
sumber
3

Saya menggunakan ekspresi reguler. 4 langkah:

  1. Buka folder root di editor Anda (saya menggunakan Visual Studio Code).
  2. Ketuk ikon Cari di sebelah kiri, dan aktifkan mode ekspresi reguler.
  3. Masukkan "+ \ n" di bilah Pencarian dan "\ n" di bilah Ganti.
  4. Klik "Ganti Semua".

Ini menghapus semua spasi di akhir setiap baris di semua file. Dan Anda dapat mengecualikan beberapa file yang tidak sesuai dengan kebutuhan ini.

roedeercuco
sumber
2

1) Banyak jawaban lain digunakan -E. Saya tidak yakin mengapa, karena itu adalah opsi kompatibilitas BSD yang tidak berdokumen . -rharus digunakan sebagai gantinya.

2) Gunakan jawaban lain -i ''. Itu harus adil -i(atau -i''jika disukai), karena -imemiliki sufiks tepat setelahnya.

3) Solusi khusus Git:

git config --global alias.check-whitespace \
'git diff-tree --check $(git hash-object -t tree /dev/null) HEAD'

git check-whitespace | grep trailing | cut -d: -f1 | uniq -u -z | xargs -0 sed --in-place -e 's/[ \t]+$//'

Yang pertama mendaftarkan alias git check-whitespaceyang mencantumkan file dengan spasi putih di belakangnya. Yang kedua menimpa sedmereka.

Saya hanya menggunakan \tdaripada [:space:]karena saya biasanya tidak melihat tab vertikal, umpan formulir, dan spasi yang tidak dapat dipecahkan. Pengukuran Anda mungkin berbeda.

Ondra Žižka
sumber
1

Inilah yang berhasil untuk saya (Mac OS X 10.8, GNU sed diinstal oleh Homebrew):

find . -path ./vendor -prune -o \
  \( -name '*.java' -o -name '*.xml' -o -name '*.css' \) \
  -exec gsed -i -E 's/\t/    /' \{} \; \
  -exec gsed -i -E 's/[[:space:]]*$//' \{} \; \
  -exec gsed -i -E 's/\r\n/\n/' \{} \;

Spasi tertinggal dihapus, menggantikan tab dengan spasi, menggantikan Windows CRLF dengan Unix \n.

Yang menarik adalah saya harus menjalankan ini 3-4 kali sebelum semua file diperbaiki, dengan semua gsedinstruksi pembersihan .

yegor256
sumber