Mengubah tab menjadi spasi di banyak file


11

Saya memiliki banyak file dengan tab yang berserakan, dan saya ingin mengonversinya menjadi spasi. Saya tahu tentang expandperintah itu, tetapi sayangnya saya harus mengetikkan setiap file yang menggunakannya. Apakah ada cara yang lebih mudah untuk melakukan ini di Linux?

Jawaban:


12

Coba yang berikut ini:

find ./ -type f -exec sed -i 's/\t/ /g' {} \;

Jika Anda ingin empat spasi, coba:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;

Itu akan mengganti setiap tab dengan satu spasi. Karena orang yang disebutkan menggunakan expand, saya berasumsi dia ingin pelurusan teks dipertahankan.
garyjohn

Anda harus 's/\t/ /g'mengganti lebih dari satu tab per baris.
Daniel Andersson

1
Sebuah percepatan substansial jika ada banyak file sedang melakukan " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (yaitu, " +" bukannya " \;"), jika findversi mendukungnya (dan saya secara pribadi belum menemukan versi apa pun yang tidak, tetapi itu bukan standar POSIX , jadi saya kira itu bisa terjadi pada beberapa sistem. Lihat " -exec command {} +" di manual). Alih-alih meluncurkan satu contoh seduntuk setiap file, ini akan membangun daftar argumen dengan sebanyak argumen nama file yang didukung sistem ( getconf ARG_MAX= 2097152 pada sistem saya), sama seperti xargs, dan dengan demikian meluncurkan sedproses yang jauh lebih sedikit .
Daniel Andersson

6
Catatan untuk setiap pengguna Mac yang menemukan ini: Versi OS X sedtidak memahami \turutan pelepasan tab. Anda bisa menggantinya dengan karakter tab literal, yang dapat Anda masukkan ke dalam shell dengan [Ctrl]+V, [Tab].
Jeremy Banks

expandmungkin lebih baik daripada sedini, seperti yang dijelaskan dalam: stackoverflow.com/a/11094620/131824
David Weinraub

6

Ada banyak cara untuk melakukan ini. Ada juga banyak cara untuk menembak diri sendiri saat melakukan ini jika Anda tidak hati-hati atau jika Anda baru mengenal Linux. Dengan asumsi bahwa Anda dapat membuat daftar file yang ingin Anda konversi, baik dengan menggunakan sesuatu seperti findatau secara manual dengan editor, cukup pipa daftar itu ke berikut ini.

while read file
do
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"
done

Salah satu cara Anda dapat menembak diri sendiri dengan melakukan itu adalah dengan membuat kesalahan ketik sehingga Anda akhirnya membuat file kosong ke semua nama file yang Anda tentukan, sehingga menghapus isi semua file Anda. Jadi berhati-hatilah dan ujilah apa pun yang Anda lakukan pertama kali pada sekumpulan kecil file yang telah Anda buat cadangannya.


3
Buat mvbersyarat pada keberhasilan expand:expand ... && mv ...
Dijeda sampai pemberitahuan lebih lanjut.

Jangan lupa expand -t 4untuk memperluas tab ke 4 spasi. Juga, metode ini dapat membuat trailing newlines. Tapi selain itu berhasil.
mgold

3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo membuat foo variabel templat untuk setiap baris input, sehingga Anda dapat merujuk ke input lebih dari sekali.

-print0dan -0beri tahu kedua perintah untuk menggunakan \ 0 sebagai pemisah baris alih-alih SPACE, jadi perintah ini berfungsi untuk jalur dengan spasi.


1
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

Cons:
file yang lebih besar dari ukuran buffer pipa ( 64KB ) terpotong

Kelebihan:
tidak ada file temp file yang
lebih besar dari ukuran buffer pipa yang terpotong


0

Ini lebih baik:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

3
Kenapa ini lebih baik? Ini bukan ide bagus untuk digunakan /tmp/ekarena jika ada yang menggunakan file itu, ini akan mengacaukannya. Seperti jika dua pengguna ingin menggunakan ini pada saat bersamaan.
Kevin Panko

0

Saya mencoba masalah ini dengan mempertimbangkan persyaratan berikut:

  • Saring file berdasarkan nama mereka, untuk memproses misalnya file .cpp atau .json saja
  • Mendukung pemrosesan paralel. Jika ada banyak file, ini dapat memberikan kecepatan tinggi
  • Solusinya harus sesuai dalam satu baris agar mudah digunakan

Persyaratan terakhir adalah yang paling sulit dipenuhi karena "memperluas" tidak memungkinkan untuk memodifikasi file di tempat.

Saya datang dengan solusi berikut:

find . -type f -regextype egrep -regex '.*\.(c|cpp|h|hpp)'  -print0 | xargs -0 -n 1 -P 10 -IFILE bash -c ' ( echo "Processing FILE..." && expand -t 4 "FILE" > /tmp/expand.$$ && mv /tmp/expand.$$ "FILE" ) || exit 255'

Berikut ini beberapa penjelasannya:

  • "find" menemukan file untuk diproses. "-regextype egrep" memungkinkan untuk memfilternya berdasarkan nama dan ekspresi reguler dalam format "egrep"
  • parameter "-type f" memastikan bahwa kami hanya akan mencocokkan file biasa, bukan untuk direktori misalnya atau apa pun yang khusus
  • parameter "-regexp" adalah ekspresi reguler itu sendiri, yang cocok dalam hal ini file apa pun yang diakhiri dengan .c, .cpp, .h atau .hpp (seluruh nama harus cocok, jadi "file.c2" tidak akan , yang kita inginkan)
  • "-print0" memerintahkan "find" untuk mencetak path file pada output standarnya dengan karakter 0 pada akhir setiap path. Bersama dengan opsi "-0" untuk "xargs", ini memungkinkan untuk meneruskan nama yang berisi kereta balik dari satu alat ke alat lainnya (bahkan jika itu adalah situasi yang cukup langka ...)
  • xargs memulai proses baru untuk setiap jalur ("-n 1"), tetapi mungkin berjalan sebanyak 10 proses secara paralel ("-P 10")
  • xargs menggunakan alias "FILE" untuk meneruskan setiap path file ke perintah, yang merupakan skrip bash
  • skrip bash memanggil "Expand" dan menyimpan hasilnya dalam file sementara yang namanya berisi ID proses saat ini ($$), sehingga semua proses yang berjalan secara paralel pada file yang diberikan menggunakan file temporer yang berbeda
  • seluruh perintah menggunakan pola (command1 && command2 && command3) sehingga proses akan berhenti jika ada sub-perintah mengembalikan kesalahan
  • jika ada kesalahan dari rantai "&&" sebelumnya, skrip bash akan mengembalikan kode keluar 255 yang akan menyebabkan xargs segera berhenti
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.