Mengapa nama folder saya berakhir seperti ini, dan bagaimana saya bisa memperbaikinya menggunakan skrip?

15

Maaf jika ada jawaban di tempat lain, saya tidak tahu bagaimana mencari masalah saya.

Saya menjalankan beberapa simulasi pada server HPC linux redhat, dan kode saya untuk menangani struktur folder untuk menyimpan output memiliki bug yang tidak menguntungkan. Kode matlab saya untuk membuat folder adalah:

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

dimana sp.run_numberbilangan bulat. Saya lupa mengonversinya menjadi string, tetapi karena alasan tertentu menjalankan mkdir(folder);(di matlab) masih berhasil. Faktanya, simulasi berjalan tanpa hambatan, dan data disimpan ke direktori yang cocok.

Sekarang, ketika struktur folder ditanyai / dicetak saya mendapatkan situasi berikut:

  • Ketika saya mencoba untuk tab autocomplete: run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • Ketika saya menggunakan ls: run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?.
  • Ketika saya mentransfer ke mac saya menggunakan rsync --progressopsi menunjukkan: run_\#003/dll dengan (saya berasumsi) nomor yang cocok dengan integer di sp.run_numberpadded menjadi tiga digit, jadi jalankan 10 adalahrun_\#010/
  • Ketika saya melihat folder di finder saya melihat run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • Melihat pertanyaan ini dan menggunakan perintah ls | LC_ALL=C sed -n lsaya dapatkan:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

Saya tidak bisa mengelola cdke folder menggunakan representasi ini.

Saya memiliki ribuan folder ini, jadi saya harus memperbaikinya dengan skrip. Manakah dari opsi ini yang merupakan representasi folder yang benar? Bagaimana saya bisa merujuk secara terprogram ke folder-folder ini sehingga saya menamainya kembali dengan nama yang diformat dengan benar menggunakan skrip bash? Dan saya rasa demi rasa ingin tahu, bagaimana mungkin ini bisa terjadi?

Phill
sumber
4
"Ketika saya mencoba untuk tab autocomplete: ... Jika saya mencoba mengetik ..." Mengapa mengetik dan tidak membiarkan autocomplete selesai jika untuk Anda? Juga ^Atidak secara harfiah ^diikuti oleh A, tetapi Ctrl-A (Anda dapat mengetiknya menggunakan Ctrl-V Ctrl-A karena Ctrl-A umumnya merupakan jalan pintas untuk shell).
muru
@muru itu tidak berhasil ... Saya sampai sejauh run_dan saya harus mengetikkan sesuatu
Phill
Maaf berkomentar sebelum saya melihat suntingan Anda, yang berhasil memasukkan saya melalui cd
Phill
Kemungkinan duplikat pilih nama file unicode di Bash
muru
9
BTW, "beberapa alasan" mengapa mkdir di matlab melakukan ini adalah karena karakter HANYA yang tidak valid dalam nama file atau direktori pada sistem file unix adalah NUL dan forward-slash /. Karakter lain apa pun yang valid, termasuk karakter kontrol. Saya tidak tahu apa yang akan dilakukan matlab jika sp.run_number adalah 0 (mungkin dibatalkan dengan kesalahan atau menghasilkan run_, karena byte NUL akan mengakhiri string nama direktori). Tentu saja, ini juga akan bermasalah untuk 16-bit (atau lebih tinggi) nilai-nilai yang memiliki byte NUL di dalamnya, dan juga akan bervariasi sesuai dengan endian-ness dari sistem yang menjalankan matlab.
cas

Jawaban:

26

Anda dapat menggunakan renameutilitas perl (alias prenameataufile-rename ) untuk mengubah nama direktori.

CATATAN: Ini tidak harus bingung dengan renamedari util-linux, atau versi lain.

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

Ini menggunakan ord()fungsi perl untuk mengganti setiap karakter kontrol dalam nama file dengan nomor urut untuk karakter itu. misalnya ^Amenjadi 1,^B menjadi 2, dll.

The -npilihan adalah untuk dry-run untuk menunjukkan apa yang rename akan dilakukan jika Anda membiarkannya. Hapus (atau ganti dengan-v untuk verbose output) untuk benar-benar mengubah nama.

The epengubah dalam s/LHS/RHS/egoperasi menyebabkan perl untuk mengeksekusi RHS (penggantian) sebagai kode perl, dan$1 merupakan data yang cocok (karakter kontrol) dari LHS.

Jika Anda ingin angka nol-empuk dalam nama file, Anda dapat menggabungkan ord()dengan sprintf(). misalnya

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

Contoh di atas berfungsi jika dan hanya jika sp.run_number dalam skrip matlab Anda berada di kisaran 0..26 (sehingga menghasilkan karakter kontrol dalam nama direktori).

Untuk menangani SETIAP karakter 1-byte (yaitu mulai dari 0..255), Anda akan menggunakan:

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

Jika sp.run_numberbisa> 255, Anda harus menggunakan unpack()fungsi perl alih-alih ord(). Saya tidak tahu persis bagaimana matlab menghasilkan int yang belum dikonversi dalam sebuah string, jadi Anda harus bereksperimen. Lihat perldoc -f unpackuntuk rincian.

misalnya yang berikut ini akan membuka nilai 8-bit dan 16-bit yang tidak ditandatangani dan zero-pad mereka menjadi 5 digit lebar:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/
cas
sumber
Terima kasih atas detailnya! Saya mencoba mengujinya dengan -nopsi, tetapi ia memberi tahu saya itu opsi yang tidak valid - informasi versi memberi saya rename from util-linux 2.23.2jadi saya tidak yakin fungsinya sama
Phill
3
itu sebabnya saya menentukan versi perl dari renameutilitas. util-linux's renamesangat berbeda, jauh kurang mampu, dan opsi baris perintah tidak kompatibel. jika Anda menjalankan debian atau sejenisnya, coba instal file-renamepaketnya. jika tidak instal paket yang sesuai untuk distro Anda. mungkin sudah diinstal, coba jalankan prenameatau file-renamebukan hanya rename.
cas
Ya saya pikir itu masalahnya. Saya akan melihat apakah saya bisa mendapatkan salah satu dari mereka untuk bekerja. Sekali lagi terima kasih telah meluangkan waktu untuk membantu saya!
Phill
11

Dan saya rasa demi rasa ingin tahu, bagaimana sih ini bisa terjadi?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

dimana sp.run_numberbilangan bulat. Saya lupa mengonversinya menjadi string, tetapi karena beberapa alasan berjalan mkdir(folder); (di matlab) masih berhasil.

Jadi, akan muncul bahwa mkdir([...])di Matlab menyatukan anggota array untuk membangun nama file sebagai string. Tetapi Anda memberikan nomor sebagai gantinya, dan angka adalah apa karakter sebenarnya di komputer. Jadi, kapan sp.run_numberitu 1, itu memberi Anda karakter dengan nilai 1, dan kemudian karakter dengan nilai2 , dll.

Mereka adalah karakter kontrol, mereka tidak memiliki simbol yang dapat dicetak, dan mencetaknya pada terminal akan memiliki konsekuensi lain. Jadi alih-alih, mereka sering diwakili oleh berbagai jenis pelarian: \001(oktal), \x01(hex), ^Asemua representasi umum untuk karakter dengan nilai1 . Karakter dengan nilai nol sedikit berbeda, itu byte NUL yang digunakan untuk menandai akhir string dalam C dan panggilan sistem Unix.

Jika Anda lebih tinggi dari 31, Anda akan mulai melihat karakter yang dapat dicetak, 32 adalah ruang (meskipun tidak terlalu terlihat), 33 = !, 34 =" dll.

Begitu,

  • run_ run_^A/ run_^B/- Yang pertama run_sesuai dengan yang dengan byte nol, string berakhir di sana. Yang lain menunjukkan bahwa shell Anda suka menggunakan menampilkan kode kontrol ^A. Notasi juga mengisyaratkan pada fakta bahwa char dengan nilai numerik 1 dapat dimasukkan sebagai Ctrl-A, meskipun Anda perlu memberitahu shell untuk menafsirkan bukan sebagai karakter kontrol, tetapi sebagai literal, Ctrl-V Ctrl-Aharus melakukan itu setidaknya di Bash.

  • ls: run_ run_? run_?- lstidak suka mencetak karakter yang tidak patut pada terminal, ia menggantikannya dengan tanda tanya.

  • rsync: run_\#003/- yang baru bagiku, tapi idenya sama, backslash menandai pelarian, dan sisanya adalah nilai numerik dari karakter. Tampaknya bagi saya bahwa angka di sini adalah oktal, seperti pada yang lebih umum \003.

  • menggunakan perintah ls | LC_ALL=C sed -n l... run_\006$ run_\a$ run_\b$ run_\t$- \a, \bdan \tC melarikan diri untuk alarm (bel), backspace dan tab, masing-masing. Mereka memiliki nilai numerik 7, 8 dan 9, jadi harus jelas mengapa mereka datang setelah itu \006. Menggunakan C escapes tersebut adalah cara lain untuk menandai karakter kontrol. Tanda-tanda dolar tertinggal menandai garis berakhir.

Adapun cd, dengan asumsi asumsi saya benar, cd run_harus pergi ke satu direktori tunggal tanpa karakter trailing aneh, dan cd run_?harus memberikan kesalahan karena tanda tanya adalah karakter gumpalan yang cocok dengan karakter tunggal, dan ada beberapa nama file yang cocok, tetapi cdhanya beberapa nama file yang cocok, tetapi hanya mengharapkan satu.

Manakah dari opsi ini yang merupakan representasi folder yang benar?

Semua dari mereka, dalam arti ...

Di Bash, Anda dapat menggunakan \000dan \x00keluar di dalam $'...'tanda kutip untuk mewakili karakter khusus, jadi $'run_\033(oktal) atau$'run_\x1b' sesuai dengan direktori dengan nilai karakter 27 (yang kebetulan ESC). (Saya tidak berpikir Bash mendukung lolos dengan angka desimal.)

jawaban cas memiliki skrip untuk mengubah nama itu, jadi saya tidak akan pergi ke sana.

ilkkachu
sumber
Jika GNU ls, ada beberapa opsi mengutip termasuk -b/ --escapedan --quoting-style=, atau QUOTING_STYLEvariabel lingkungan, untuk mengontrol bagaimana karakter yang tidak dicetak ditampilkan. Saya tidak berpikir ada pilihan untuk membuatnya lebih memilih oktal lolos dari versi karakter.
Toby Speight
3

Cara termudah adalah membuat nama file yang salah dan nama file yang benar di lingkungan yang sama di mana kecelakaan terjadi, dan kemudian hanya memindahkan / mengganti nama folder ke nama yang benar.

Untuk menghindari tabrakan antara nama yang ada, lebih baik gunakan folder tujuan lain.

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

Jika memungkinkan, saya lebih suka memperbaiki skrip dan menjalankannya lagi; memperbaiki beberapa bug post mortem aneh mungkin lebih mahal dan dapat menimbulkan masalah baru.

Semoga berhasil!

Peter
sumber