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

30

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

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

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

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

ZirconCode
источник
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
jimmij
источник
Хм, я не знал об этих операторах glob, я прочитал о них и немного узнал (спасибо), это решает проблему, которая у меня возникла: один странный файл в моем каталоге. Теперь у меня есть эта проблема с большим множеством файлы, я должен задать новый вопрос или обновить этот?
ZirconCode
Я принял ваш ответ, я опубликую второй сценарий завтра, когда у меня будет время. Спасибо вам за помощь.
ZirconCode
6

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

user86880
источник
Это достаточно приличный удар. Вы могли бы 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
Volker Siegel
источник
2

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

mv \U000491ebabc.mp3 abc.mp3

переименовать ♫abc.mp3.

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

Barmar
источник
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 использует другую терминологию (параметр и имя файла расширение).

Fólkvangr
источник
1

Используйте zshи введите то, что будет дальше. ZSH поддерживает нечеткое автозаполнение и может справиться с этим. (Особенно хорошо с плагином OH-MY-ZSH .)

Мартин Тома
источник
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
    

    который позволяет вам ударить префикс перед старым именем. Если вы выбрали уникальный префикс, это позволит вам использовать автозаполнение.

G-Man говорит: «Восстанови Монику»
источник