mengubah nama massal (atau menampilkan dengan benar) file dengan karakter khusus

20

Saya memiliki banyak direktori dan subdirektori yang berisi file dengan karakter khusus, seperti file ini:

robbie@phil:~$ ls testsktest.txt 
test?sktest.txt

Temukan mengungkapkan urutan pelarian:

robbie@phil:~$ find testsktest.txt -ls 
424512 4000 -rwxr--r-x   1 robbie   robbie    4091743 Jan 26 00:34 test\323sktest.txt

Satu-satunya alasan saya bahkan dapat mengetik nama mereka di konsol adalah karena penyelesaian tab. Ini juga berarti saya dapat mengganti nama secara manual (dan menghapus karakter khusus).

Saya telah mengatur LC_ALL ke UTF-8, yang sepertinya tidak membantu (juga tidak pada shell baru):

robbie@phil:~$ echo $LC_ALL
en_US.UTF-8

Saya terhubung ke mesin menggunakan ssh dari mac saya. Ini adalah instalasi Ubuntu:

robbie@phil:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=7.10
DISTRIB_CODENAME=gutsy
DISTRIB_DESCRIPTION="Ubuntu 7.10"

Shell adalah Bash, JANGKA diatur ke warna xterm.

File-file ini telah ada di sana cukup lama, dan mereka belum dibuat menggunakan instalasi Ubuntu itu. Jadi saya tidak tahu apa pengaturan sistem pengkodean dulu.

Saya sudah mencoba beberapa hal di sepanjang baris:

find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'

Tetapi saya tidak dapat menemukan solusi yang melakukan semua yang saya inginkan:

  1. Identifikasi semua file yang memiliki karakter yang tidak dapat diputar (terlalu banyak mengabaikan hal di atas)
  2. Untuk semua file di pohon direktori (secara rekursif), jalankan mv oldname newname
  3. Secara opsional, kemampuan untuk mentransliterasi karakter khusus seperti ä ke (tidak diperlukan, tetapi akan luar biasa)

ATAU

  1. Tampilkan semua file ini dengan benar (dan tidak ada kesalahan dalam aplikasi saat mencoba membukanya)

Saya punya bit dan potongan, seperti iterasi semua file dan memindahkannya, tetapi mengidentifikasi file dan memformatnya dengan benar untuk perintah mv tampaknya menjadi bagian yang sulit.

Setiap informasi tambahan tentang mengapa mereka tidak ditampilkan dengan benar, atau bagaimana "menebak" pengkodean yang benar juga diterima. (Saya sudah mencoba convmv tetapi sepertinya tidak melakukan apa yang saya inginkan: http://j3e.de/linux/convmv/ )

RobbieV
sumber
Jawaban tunggal di bawah ini mengikuti cara pertama (temukan mereka dan ganti nama ke pengkodean baru Anda), tetapi cara kedua juga akan menarik: sekarang, ketika Anda tahu pengkodean yang digunakan untuk nama file jarak jauh, cara ssh ke host jarak jauh seperti cara agar nama file ditampilkan dengan benar (dan dapat dikelola dengan mengetikkan nama mereka dengan keyboard Anda)?
imz - Ivan Zakharyaschev

Jawaban:

21

Saya kira Anda melihat karakter yang tidak valid ini karena namanya berisi urutan byte yang tidak valid UTF-8. Nama file pada sistem file unix yang khas (termasuk milik Anda) adalah string byte, dan tergantung pada aplikasi untuk memutuskan encoding apa yang akan digunakan. Saat ini, ada kecenderungan untuk menggunakan UTF-8, tetapi itu tidak universal, terutama di lokal yang tidak pernah bisa hidup dengan ASCII biasa dan telah menggunakan pengkodean lain sejak sebelum UTF-8 bahkan ada.

Cobalah LC_CTYPE=en_US.iso88591 lsuntuk melihat apakah nama file masuk akal di ISO-8859-1 (latin-1). Jika tidak, coba tempat lain. Perhatikan bahwa hanya LC_CTYPEpengaturan lokal yang penting di sini.

Di lokal UTF-8, perintah berikut akan menampilkan semua file yang namanya tidak valid UTF-8:

grep-invalid-utf8 () {
  perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print'
}
find | grep-invalid-utf8

Anda dapat memeriksa apakah mereka lebih masuk akal di lokal lain dengan recode atau iconv :

find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8

Setelah Anda menentukan bahwa sekelompok nama file berada dalam pengkodean tertentu (misalnya latin1), salah satu cara untuk menamainya adalah

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Ini menggunakan perintah perl rename yang tersedia di Debian dan Ubuntu. Anda dapat meneruskannya -nuntuk menunjukkan apa yang akan dilakukan tanpa benar-benar mengganti nama file.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih saya akan mencoba beberapa dari hal ini hari ini! Sepertinya ini akan menjadi jawaban yang diterima :)
RobbieV
Temuan | Perintah grep '[[: print:]]' tampaknya hanya mengembalikan semua file. Bukankah seharusnya UTF-8 kompatibel dengan banyak pengkodean lainnya dengan karakter "normal"?
RobbieV
@RobbieV: Saya salah ketik dan bermaksud grep [^[:print:]]mencari karakter yang tidak patut. Tapi saya baru saja diuji dengan GNU grep dan urutan UTF-8 tidak valid tidak tertangkap [^[:print:]](yang masuk akal karena mereka bukan karakter yang tidak patut, mereka bukan karakter sama sekali). Saya telah mengedit posting saya dengan cara yang lebih lama dalam menangkap garis dengan urutan utf8 yang tidak valid. Perhatikan bahwa saya juga telah memperbaiki arah recodedan iconvcontoh.
Gilles 'SO- stop being evil'
Itu bekerja dengan sempurna. Mencoba semua perintah kecuali ikonv, dan semuanya bekerja seperti yang diharapkan. Sihir murni!
RobbieV
Bahkan pengkodean latin1 yang disarankan adalah yang benar :)
RobbieV
1

Saya tahu ini adalah pertanyaan lama tetapi saya telah mencari sepanjang malam untuk solusi yang sama. Saya menemukan beberapa tips bermanfaat tetapi mereka tidak melakukan apa yang saya butuhkan, jadi saya harus mencampur dan mencocokkan beberapa untuk mendapatkan hasil yang benar yang saya cari

untuk hanya menghapus karakter khusus dan menggantinya dengan tanda (.)

for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done

untuk digunakan dalam cronjob, saya melakukan yang berikut untuk menjalankan setiap menit

*/1 * * * * cd /path/to/files/ && for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done >/dev/null 2>&1

Saya harap seseorang menemukan ini bermanfaat karena telah membuat hari saya :)

Topps70
sumber
(1) Untuk kejelasan, Anda mungkin ingin perubahan `…`untuk $(…)- melihat ini , ini , dan ini . (2) Anda harus selalu mengutip referensi variabel shell Anda (misalnya, "$f") kecuali Anda memiliki alasan yang baik untuk tidak melakukannya, dan Anda yakin Anda tahu apa yang Anda lakukan. Ini berlaku bahkan untuk echo "$f" | sed …. Ini juga berlaku untuk seluruh $(…)(atau `…`) ekspresi; yaitu mv "$f" "$(echo "$f" | sed "…")",. … (Lanjutan)
Scott
(Lanjutan) ... (3) Anda harus mengatakan , untuk melindungi terhadap nama file yang dimulai dengan . (4) Jika Anda memiliki file bernama "foo ♥ bar.txt" dan "foo ♠ bar.txt", ini akan (mencoba untuk) mengganti nama keduanya menjadi "foo.bar.txt", mungkin menyebabkan semua kecuali satu file yang akan dihancurkan. (5) Mengapa kamu ingin melakukan ini sekali setiap menit? mv -- "$f" …-
Scott
Saya memiliki skrip torrent yang mengunduh file secara otomatis. dan terkadang beberapa file memiliki karakter di dalamnya yang membuat pengunggah tidak aktif. jadi dengan hanya mengganti nama file dengan karakter khusus, cron saya memperbaiki semua masalah saya dan pengunggah melakukan tugasnya dengan lancar.
Topps70
jadi (fi'le tha ini, t was - down_loaded.ext) berubah menjadi (this.fi.le.tha.t.was.down.loaded.ext)
Topps70
0

Sekarang, ketika Anda tahu pengkodean mana yang digunakan untuk nama file pada ujung jarak jauh ("latin1" - sesuai dengan komentar pada jawaban pertama), Anda juga dapat mengikuti cara kedua - jalankan termninal lokal dan ssh sedemikian rupa cara nama file jarak jauh ditampilkan dengan benar (daripada cara pertama: ganti nama mereka) .

Seperti saya , Anda dapat memulai terminal secara lokal yang akan berfungsi dalam pengkodean khusus itu, mungkin, seperti ini:

LC_ALL = en_US.latin1 xvt &

xvt singkatan dari program terminal Anda.

Mungkin, lokal yang ada disebut en_US.iso88591, dan tidak en_US.latin1, seperti yang saya duga.

imz - Ivan Zakharyaschev
sumber
0

Ini tidak memenuhi persyaratan massal, tetapi saya baru saja mengalami masalah yang sama di mana saya memiliki beberapa versi file dengan nama yang sama yang hanya berbeda oleh satu karakter aneh. Sayangnya ini berarti bahwa saya tidak dapat mengganti nama pelanggar menggunakan trik wildcard yang biasa saya gunakan.

Pada akhirnya saya menggunakan Filezilla untuk terhubung sebagai klien SFTP, melihat-lihat file dan menamainya menggunakan GUI. Filezilla menangani karakter cerdik dengan cukup baik.

kabadisha
sumber