Робота з іменами файлів із спеціальними першими символами (наприклад, ♫)


30

Нещодавно я натрапив на файл, ім'я якого починається з символу "♫". Я хотів скопіювати цей файл, ввести його ffmpegта посилати його різними іншими способами у терміналі. Я зазвичай автоматично заповнюю дивні імена файлів, але це не вдається, оскільки я не можу навіть ввести першу букву.

Я не хочу переходити на мишу, щоб виконувати маневр копіювання та вставки. Я не хочу запам’ятовувати купу кодів для можливих сценаріїв. Моє спеціальне рішення полягало в тому, щоб увімкнути vim, вставити !lsта скопіювати відповідний символ, а потім вийти та вставити його в термінал. Це спрацювало, але досить жахливо.

Чи є простіший спосіб впоратися з подібними сценаріями?

ПРИМІТКА: Я використовую рибну оболонку, якщо вона змінить речі.


7
Чи можете ви використовувати інші частини файлу для формування регексу для роботи з ним? *restoffile.aviчи щось подібне?
slm

1
У цьому випадку решта назва була сумішшю Канджі та Катакана (японський сценарій), так що не з легкістю.
ZirconCode

3
Розумів, просто думав, що запитаю. Чи вирішує це тоді відповідь Джиммі? Також ви не проти вставити скріншот файлів, які ображають це? Можливо, буде корисним іншим, хто може прочитати це згодом.
slm

1
Я зараз намагаюся змусити його працювати. Я не знаю, як розмістити скриншот, але виконання наступних команд дасть вам мою проблему:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode

1
За допомогою zsh ви можете скористатися параметрами, щоб вкладка дала вам меню, з якого ви можете вибрати відповідний файл.
Кевін

Відповіді:


35

Якщо перший символ імені файлу друкується, але не буквено-цифровий чи пробіл, ви можете використовувати [[:punct:]]глобальний оператор:

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt

Хм, я не знав про ці глобальні оператори, я прочитав про них і трохи дізнався (спасибі), це вирішує проблему, яку я мав - це єдиний дивний файл у моєму реєстрі. Зараз у мене ця проблема з великою безліччю Файли, мені слід задати нове запитання чи оновити це?
ZirconCode

Я прийняв вашу відповідь, другий сценарій я опублікую завтра, коли встигну. Дякую за допомогу.
ZirconCode

6

Найпростіше, що трапляється у мене, - це ls [^a-zA-Z0-9]*і робить для мене трюк, але відповідь тердона краще в тому, щоб привернути увагу до варіанту оболонки extglob або навіть підходу незалежно від оболонки.


Це досить пристойний удар. Ви могли б ls [^[:alnum:]]*за те саме. Але краще використовувати клас символів, який він є , а не клас (и), який він не є ; отже ls [[:punct:]]*, список цього файлу.
Багатий

6

ls має деякі перемикачі (наприклад - ім'я котирування, --escape, --literal) для роботи з недрукованими символами, але в цьому випадку здається, що символ є "друкованим", але не "типним" (принаймні на моїй клавіатурі! ), тому жоден з цих комутаторів, здається, не допомагає.

Тому, як загальний підхід "грубої сили" для позбавлення файлів з будь-якими символами в їх іменах, ви можете зробити це:

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

Знайдіть рядок, що містить файл-порушення. Цілком ймовірно, що це буде 1-й рядок, але скажімо, це 5-й. Друкований рядок 5 і шістнадцятковий кодують його:

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

Ігноруючи символ 0a (новий рядок), побудуйте рядовий рядок і використовуйте параметр -e ехо для перекладу виходу:

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

Тепер ви можете скопіювати / перемістити / видалити його так:

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

Крім того, якщо ви не обмежилися використанням скрипту оболонки, ви можете зробити це в Python так:

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

Використовуючи такий підхід, ви можете обробити безліч файлів, просто потрібно записати логіку вибору правильних файлів та перейменувати їх без клобінгу тощо:

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!'

5

Аналогічний підхід був би перерахувати всі файли, які не починаються з "нормальних" символів. У bash ви можете це зробити

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

Однак це, здається, не доступне fish, тому ви можете використовувати findзамість цього:

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

4

Перейменуйте символьні посилання

Один із підходів до обробки імен файлів спеціальними символами - як перші символи чи в інших місцях у імені файлу - це перейменування на більш прості імена .

Це можна використовувати, навіть якщо вам потрібно зберегти оригінальні назви файлів : Перейменуйте копію імен.
Це можна зробити, скопіювавши файли, але також створивши символьні посилання або тверді посилання на файли, і перейменувати їх. cpстворює символьні посилання замість копій з опцією -s( -lдля твердих посилань ).

Використовуйте "детокс", щоб очистити імена

Для перейменування для очищення імен файлів detoxможна використовувати; Він перейменовує файли, щоб очистити імена файлів згідно з різними правилами, визначеними у detoxrcфайлі. За замовчуванням символи UTF8 просто видаляються; З опцією -s utf_8-onlyвони замінюються на _:

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


"детокс" на символьних посиланнях

У поєднанні з роботою над посиланнями, як описано вище:

$ 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

2

Я не використовую fish, але в документації йдеться про те, що ви можете ввести символ Unicode, встановивши його шестнадцятковий код символів \u(для 16-бітових символів) або \U(для 32-бітових символів). Я думаю, що код є 491eb, так що ви можете зробити:

mv \U000491ebabc.mp3 abc.mp3

перейменувати ♫abc.mp3.

Зауважте, що вам потрібні провідні нулі, інакше abcв кінці будуть розглядатися як шістнадцяткові цифри, так і частина символьного коду; для 32-бітного символу потрібно ввести 8 цифр.


2

Я не знаю, чи це було так у 2014 році, коли ви задавали питання, але в сучасних версіях fish(станом на 2019 рік) ви можете натиснути Tabдвічі, щоб отримати вибір у стилі zsh, де ви можете використовувати клавіші зі стрілками для візуально виберіть потрібний файл, не вводячи жодної частини імені файлу.


2

Риба не підтримує подвійні символи cket за конструкцією.

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

Команда не виконує пошук в прихованих каталогах і відображає імена файлів , які не починаються з символів letters, digits, . _ -(див документації find).

Примітка: $argv це спеціальна змінна масиву (оболонка Fish), яка містить аргументи функції, тому основна команда може отримувати будь-яке вираження (наприклад, псевдонім ).

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

¹ Насправді, риба підтримує розширення кронштейна (розширення змінного масиву) , але Bash використовує іншу термінологію (параметр і ім'я файлу розширення).



0

Ви не сказали, чи хочете ви зберегти ці проблемні назви файлів. Одним із варіантів рішення може бути «виправити» проблему раз і назавжди, перейменувавши (деякі чи всі) ваші файли на імена, які ви можете набрати, запустивши цей сценарій:

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

У цьому списку буде вказано ваші існуючі імена файлів, за якими слідує кожне ...?. Просто введіть, Enterщоб залишити файл таким, який є; або введіть нове ім'я, щоб перейменувати його. Цей -iпараметр призведе до того, що ви попросите підтвердити перезапис, якщо вказати ім'я іншого існуючого файлу.

Цей сценарій можна змінити декількома способами:

  • Ви можете змінити підстановку ( *) на щось більш обмежувальне, наприклад *.avi *.mov, так що вам не доведеться переглядати кожен файл.
  • Ви можете змінити mv на cp, щоб ви зберегли копію файлу з його поточним іменем та створили (тимчасову?) Копію з ім'ям, що вводиться.
  • Ви можете створити нове ім’я файлу, яке базується на існуючому імені файлу. Наприклад,

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

    що дозволяє ляпати префікс перед старим іменем. Якщо ви вибрали унікальний префікс, це дозволить вам використовувати автоматичне завершення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.