Работа с именами файлов со специальными первыми символами (например, ♫)


30

Недавно я натолкнулся на файл, имя которого начинается с символа «♫». Я хотел скопировать этот файл, ffmpegвставить его и ссылаться на него различными другими способами в терминале. Я обычно автоматически заполняю странные имена файлов, но это не удается, поскольку я даже не могу набрать первую букву.

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

Есть ли более простой способ справиться с такими сценариями?

ПРИМЕЧАНИЕ: я использую рыбную раковину, если она что-то меняет.


7
Можете ли вы использовать другие части файла, чтобы сформировать регулярное выражение для работы с ним? *restoffile.aviили как то так?
— SLM

1
В данном случае оставшееся имя представляло собой смесь кандзи и катаканы (японская письменность), поэтому не легко.
— ZirconCode

3
Понял, просто подумал, что спрошу. Решает ли ответ Джимми это тогда? Также не могли бы вы вставить скриншот оскорбительных файлов? Вероятно, это будет полезно для других, которые могут прочитать это позже.
— slm

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

1
С zsh вы можете использовать опции, чтобы вкладка давала вам меню, из которого вы можете выбрать соответствующий файл.
— Кевин

Ответы:


35

Если первый символ имени файла печатается, но не содержит буквенно-цифровых символов или пробелов, вы можете использовать [[:punct:]]оператор glob:

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

Хм, я не знал об этих операторах glob, я прочитал о них и немного узнал (спасибо), это решает проблему, которая у меня возникла: один странный файл в моем каталоге. Теперь у меня есть эта проблема с большим множеством файлы, я должен задать новый вопрос или обновить этот?
— ZirconCode

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

6

Самое простое, что приходит мне в голову, это ls [^a-zA-Z0-9]*то, что мне нужно, но ответ Тердона лучше привлечь внимание к опции оболочки extglob или даже к независимому от оболочки подходу.


Это достаточно приличный удар. Вы могли бы ls [^[:alnum:]]*за то же самое. Но это лучше использовать класс символов , то есть , а не класс (ы) это не ; следовательно ls [[:punct:]]*, перечислю этот файл.
— Богатое

6

У ls есть несколько ключей (например, --quote-name, --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 (перевод строки), создайте escape-строку и используйте параметр -e echo для перевода escape-символов:

$ 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

Рыба не поддерживает символы-скобки design по дизайну.

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

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

Примечание: $argv это специальная переменная массива (Fish shell), которая содержит аргументы функции, поэтому основная команда может получить любое выражение (например, псевдоним ).

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.