Berurusan dengan nama file dengan karakter pertama spesial (mis. ♫)

30

Baru-baru ini saya menemukan file yang namanya dimulai dengan karakter '♫'. Saya ingin menyalin file ini, memasukkannya ke dalam ffmpeg, dan merujuknya dengan berbagai cara lain di terminal. Saya biasanya secara otomatis melengkapi nama file yang aneh tetapi ini gagal karena saya bahkan tidak bisa mengetik huruf pertama.

Saya tidak ingin beralih ke mouse untuk melakukan manuver salin-tempel. Saya tidak ingin menghafal banyak kode untuk kemungkinan skenario. Solusi ad hoc saya adalah beralih ke vim, rekatkan !lsdan salin karakter yang dimaksud, lalu keluar dan rekatkan ke terminal. Ini berhasil tetapi cukup mengerikan.

Apakah ada cara yang lebih mudah untuk menangani skenario seperti itu?

CATATAN: Saya menggunakan kerang ikan jika itu mengubah keadaan.

Kode Zirkon
sumber
7
Bisakah Anda menggunakan bagian lain dari file untuk membentuk regex agar bisa bekerja dengannya? *restoffile.aviatau sesuatu seperti ini?
slm
1
Dalam hal ini nama yang tersisa adalah campuran Kanji dan Katakana (aksara Jepang), jadi tidak dengan mudah.
ZirconCode
3
Dipahami, hanya berpikir saya akan bertanya. Apakah jawaban jimmij menyelesaikannya? Maukah Anda menempelkan tangkapan layar file yang menyinggung? Ini mungkin akan bermanfaat bagi orang lain yang mungkin membaca ini nanti.
slm
1
Saya mencoba membuatnya berfungsi sekarang. Saya tidak tahu cara memposting screeny tetapi menjalankan perintah berikut akan memberi Anda masalah tiruan saya:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode
1
Dengan zsh, Anda dapat menggunakan opsi agar tab memberi Anda menu tempat Anda dapat memilih file yang sesuai.
Kevin

Jawaban:

35

Jika karakter pertama nama file dapat dicetak tetapi bukan alfanumerik atau spasi putih Anda dapat menggunakan [[:punct:]]operator glob:

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt
jimmij
sumber
Hmm saya tidak tahu tentang operator glob ini, saya membaca tentang mereka dan belajar sedikit (terima kasih), itu memecahkan masalah yang saya miliki yang merupakan file aneh tunggal di dir saya. Sekarang saya punya masalah ini dengan banyak sekali file, haruskah saya mengajukan pertanyaan baru atau memperbarui yang ini?
ZirconCode
Saya telah menerima jawaban Anda, saya akan memposting skenario kedua besok ketika saya punya waktu. Terima kasih atas bantuannya.
ZirconCode
6

Yang paling sederhana yang terjadi pada saya adalah ls [^a-zA-Z0-9]*dan itu memang trik untuk saya, tetapi jawaban terdon lebih baik dalam membawa perhatian pada opsi shell extglob atau bahkan pendekatan shell-independent.

pengguna86880
sumber
Ini adalah tikaman yang cukup baik. Anda dapat ls [^[:alnum:]]*melakukan hal yang sama. Tapi itu lebih baik menggunakan kelas karakter itu adalah , daripada kelas (es) itu tidak ; maka ls [[:punct:]]*akan mencantumkan file ini.
Kaya
6

ls memiliki beberapa sakelar (seperti --quote-name, --escape, --literal) untuk berurusan dengan karakter yang tidak patut dicetak, tetapi dalam hal ini tampaknya karakter tersebut "dapat dicetak" tetapi tidak "dapat diketik" (setidaknya pada keyboard saya! ), jadi tak satu pun dari switch ini tampaknya membantu.

Oleh karena itu, sebagai pendekatan umum "brute force" untuk menyingkirkan file dengan karakter apa pun dalam namanya, Anda dapat melakukan ini:

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ♫
     2  f1.txt
     3  f2.txt

Temukan baris yang berisi file yang menyinggung. Sangat mungkin itu akan menjadi baris ke-1, tetapi katakanlah itu adalah baris ke-5. Cetak baris 5 dan hex enkode:

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....

Mengabaikan karakter 0a (baris baru), membuat string pelarian, dan menggunakan opsi -e dari gema untuk menerjemahkan escapes:

$ echo -e '\xe2\x99\xab'
♫

Sekarang Anda dapat menyalin / memindahkan / menghapusnya seperti ini:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘♫’ -> ‘better_name’

Juga, jika Anda tidak dibatasi untuk menggunakan skrip shell, Anda bisa melakukannya dengan Python seperti ini:

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
♫
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')

Dengan menggunakan pendekatan ini, Anda dapat memproses banyak file, Anda hanya perlu menulis logika untuk memilih file yang benar, dan mengganti nama file tersebut tanpa mengganggu, dll:

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'
Matthew Breithaupt
sumber
5

Pendekatan serupa akan membuat daftar semua file yang tidak dimulai dengan karakter "normal". Di bash kamu bisa melakukan ini

$ shopt -s extglob
$ ls !([[:alpha:]]*)

Namun, itu sepertinya tidak tersedia untuk fish, jadi Anda bisa menggunakannya findsebagai gantinya:

$ find . -type f -not -name '[[:alpha:]]*'
terdon
sumber
4

Ganti nama symlinks

Salah satu pendekatan untuk menangani nama file dengan karakter khusus - sebagai karakter pertama atau tempat lain dalam nama file adalah mengubah nama menjadi nama yang lebih sederhana .

Ini dapat digunakan bahkan jika Anda perlu menyimpan nama file asli : Ganti nama salinan nama file.
Itu bisa dilakukan dengan menyalin file, tetapi juga dengan membuat symlink atau hardlink ke file, dan mengganti nama ini. cpmembuat symlink alih-alih salinan dengan opsi -s( -luntuk hardlink).

Gunakan "detox" untuk membersihkan nama

Untuk mengganti nama untuk membersihkan nama file, detoxdapat digunakan; Itu mengubah nama file untuk membersihkan nama file sesuai dengan berbagai aturan sebagaimana didefinisikan dalam detoxrcfile. Secara default, karakter UTF8 baru saja dihapus; Dengan opsi -s utf_8-onlymereka digantikan oleh _:

$ touch '♫ 漢字カ' ♫foo
$ ls -1
♫foo
♫ 漢字カ
$ detox -s utf_8-only * 
$ ls -1                
_ ___
_foo


"detoksifikasi" pada symlinks

Dikombinasikan dengan bekerja pada symlink seperti dijelaskan di atas:

$ mkdir orig
$ cd orig 
$ touch '♫ 漢字カ' ♫foo
$ cd ..
$ mkdir clean
$ cd clean 
$ cp -s ../orig/* .
$ ll               
lrwxrwxrwx 1 14 Oct  8 05:52 ♫foo -> ../orig/♫foo
lrwxrwxrwx 1 21 Oct  8 05:52 ♫\ 漢字カ -> ../orig/♫\ 漢字カ
$ ls -1
♫foo
♫ 漢字カ
$ detox --special -s utf_8-only *
$ ll                                
lrwxrwxrwx 1 21 Oct  8 05:52 _\ ___ -> ../orig/♫\ 漢字カ
lrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/♫foo
Volker Siegel
sumber
2

Saya tidak menggunakan fish, tetapi dokumentasi mengatakan bahwa Anda dapat memasukkan karakter Unicode dengan awalan kode karakter hex dengan \u(untuk karakter 16-bit) atau \U(untuk karakter 32-bit). Saya pikir kodenya adalah 491eb, jadi Anda bisa melakukannya:

mv \U000491ebabc.mp3 abc.mp3

untuk mengganti nama ♫abc.mp3.

Perhatikan bahwa Anda memerlukan nol di depan, jika tidak, abcpada akhirnya akan diperlakukan sebagai digit hex, dan bagian dari kode karakter; untuk karakter 32-bit Anda harus memasukkan 8 digit.

Barmar
sumber
2

Saya tidak tahu apakah itu sudah terjadi pada tahun 2014 ketika Anda mengajukan pertanyaan, tetapi dalam versi saat ini fish(pada 2019), Anda dapat menekan Tabdua kali, untuk mendapatkan pilihan gaya zsh di mana Anda dapat menggunakan tombol panah untuk pilih secara visual file yang Anda inginkan tanpa harus mengetikkan bagian mana pun dari nama file.

Stéphane Chazelas
sumber
2

Ikan tidak mendukung wildcard braket ¹ sesuai desain.

function find_special_filename
    find ! -path './.*' -name '[^-.a-zA-Z0-9_]*' $argv
end

Perintah tidak mencari di direktori dan menampilkan disembunyikan nama file yang tidak dimulai dengan karakter letters, digits, . _ -(cf dokumentasifind ).

Catatan: $argv adalah variabel array khusus (shell Ikan) yang berisi argumen fungsi karena itu perintah yang mendasari dapat menerima ekspresi apa pun (misalnya alias ).

find_special_filename -exec mv '{}' misc/ \;

¹ Faktanya, Fish mendukung ekspansi braket (ekspansi variabel array) tetapi Bash menggunakan terminologi lain (ekspansi parameter dan nama file).

Fólkvangr
sumber
1

Gunakan zshdan ketik apa yang terjadi selanjutnya. ZSH mendukung fuzzy auto complete dan dapat menanganinya. (Sangat bagus dengan plugin OH-MY-ZSH .)

Martin Thoma
sumber
0

Anda tidak mengatakan apakah Anda ingin menyimpan nama file yang bermasalah ini. Salah satu solusinya mungkin dengan "memperbaiki" masalah sekali dan untuk semua dengan mengubah nama (beberapa atau semua) file Anda menjadi nama yang dapat Anda ketik dengan menjalankan skrip ini:

#!/bin/sh
for old in *
do
      printf "%s ...? " "$old"
      if read new  &&  [ "$new" != "" ]
      then
             mv -i "$old" "$new"
      fi
done

Ini akan mencantumkan nama file Anda yang ada, masing-masing diikuti oleh ...?. Ketik sajaEnter untuk meninggalkan file apa adanya; atau ketik nama baru untuk mengganti nama itu. The -ipilihan akan menyebabkan itu untuk meminta Anda untuk mengkonfirmasi Timpa jika Anda menentukan nama file lain yang ada.

Script ini dapat dimodifikasi dengan beberapa cara:

  • Anda dapat memodifikasi wildcard ( *) menjadi sesuatu yang lebih ketat, misalnya,*.avi *.mov , jadi Anda tidak perlu melihat setiap file.
  • Anda dapat mengubah mvke cp, jadi Anda menyimpan salinan file dengan nama saat ini dan membuat salinan (sementara?) Dengan nama yang dapat diketik.
  • Anda bisa membuat nama file baru yang didasarkan pada nama file yang ada. Sebagai contoh,

    if read pfx  &&  [ "$pfx" != "" ]
    then
            mv -i "$old" "$pfx$old"
    fi
    

    yang memungkinkan Anda menampar awalan di depan nama lama. Jika Anda memilih awalan unik, ini akan memungkinkan Anda menggunakan pelengkapan otomatis.

G-Man Mengatakan 'Reinstate Monica'
sumber