Переименуйте много файлов со всеми типами символов с мобильностью POSIX

Если у Вас есть X активных передач (ssh -X, ForwardX11 в ~/.ssh/config, или любой другой метод), можно управлять X выборами от оболочки:

printf %s "$PWD" | xsel -i

В зависимости от Вашего эмулятора терминала можно хотеть установить БУФЕР ОБМЕНА (xsel -bi) вместо ОСНОВНОГО выбора (xsel -p). Можно также использовать ВТОРИЧНЫЙ выбор (xsel -si).

Можно использовать среднюю кнопку мыши для вставки ОСНОВНОГО выбора, или (в некоторых терминалах) БУФЕР ОБМЕНА с Ctrl+V, или можно использовать xsel (или xsel -s или xsel -b) в оболочке с другой стороны.

Существуют другие возможные рабочие процессы, включая, например, обратное соединение SSH, ~ Escape или zssh. См., что SSH легко копирует файл в локальную систему, Загрузка файл по активной сессии SSH. Вы могли также смонтировать удаленную файловую систему по sshfs.

2
08.03.2012, 21:16
2 ответа

На самом деле, for i in *; do something; done рассматривает каждое имя файла правильно, за исключением того, что имена файлов, которые начинаются с a . исключены из подстановочного соответствия. Соответствовать всем файлам (кроме . и ..) портативно, соответствие * .[!.]* ..?* и пропустите любой несуществующий файл, следующий из шаблона несоответствия, оставляемого неповрежденным.

При испытании проблем это, вероятно, потому что Вы не заключили в кавычки $i правильно позже. Всегда помещайте двойные кавычки вокруг подстановок переменных и управляйте заменами: "$foo", "$(cmd)" если Вы не предназначаете полевое разделение и globbing для случая.

Если необходимо передать имя файла внешней команде (Вы не делаете, здесь), осторожны это echo "$foo" не всегда печатает $foo буквально. Несколько оболочек выполняют расширение обратной косой черты и несколько значений $foo начало - будет рассматриваться как опцию. Безопасный и совместимый POSIX способ распечатать строку точно

printf '%s' "$foo"

или printf '%s\n' "$foo" добавить новую строку в конце. Другая вещь не упустить состоит в том, что замена команды удаляет запаздывание новых строк; если необходимо сохранить новые строки, возможный прием должен добавить несимвол новой строки к данным, удостоверьтесь, что преобразование сохраняет этот символ, и наконец усеките этот символ. Например:

mangled_file_name="$(printf '%sa' "$file_name" | tr -sc '[:alnum:]-+_.' '[_*]')"
mangled_file_name="${mangled_file_name%a}"

Для извлечения md5sum файла постарайтесь не иметь имя файла в md5sum вывод, так как это будет мешать разделять. Передайте данные md5sumстандартный вход.

Обратите внимание что md5sum команда не находится в POSIX. Несколько вариантов Unix имеют md5 или ничто вообще. cksum POSIX, но склонный к коллизии.

Посмотрите Захват расширения в имени файла о том, как получить расширение файла.

Давайте соединим все это (непротестированное). Все здесь работает под любой оболочкой POSIX; Вы могли получить немного, но не очень, от функций удара.

for old_name in * .[!.]* ..?*; do
  if ! [ -e "$old_name" ]; then continue; fi
  hash=$(md5sum <"$old_name")
  case "$old_name" in
    *.*.gz|*.*.bz2)                   # double extension
      ext=".${old_name##*.}"
      tmp="${old_name%.*}"
      ext=".${old_name##*.}$ext";;
    ?*.*) ext=".${old_name##*.}";;    # simple extension
    *) ext=;;                         # no extension
  esac
  mv -- "$old_name" "$hash$ext"
done

Обратите внимание, что я не рассматривал случай, где уже существует конечный файл указанным именем. В частности, если у Вас будут существующие файлы, имя которых похоже на Вашу принятую конвенцию, но где часть контрольной суммы не соответствует содержанию файла и вместо этого соответствует части некоторого другого файла с тем же расширением, что происходит, будет зависеть от относительного лексикографического порядка имен файлов.

6
27.01.2020, 21:49

Так как это - довольно сложный вопрос, я просто предоставлю несколько инструкций:

  • Переменные имени файла двойной кавычки везде. Это избежит почти всех пробельных проблем из-за разделения слова.
  • Переменные внутри $() должны быть заключены в кавычки точно так же, как вне этой конструкции. Никакой дополнительный выход не необходим.
  • $() и `` конструкции разделяют запаздывание новых строк, таким образом, необходимо добавить другой символ и затем разделить его вне $() конструкция:

    varx="$([command which might print a value ending in \n]; echo x)"
    var="${varx%x}"
    
  • -- в командах необходимо для разделения аргументов от имен файлов, так как имена файлов могут запуститься с --, и был бы поэтому обработан как параметры.
    • find не поддерживает этот синтаксис, так использование readlink получить полный путь, который по определению запускается с наклонной черты или удостоверяется что путь, данный find является уже абсолютным или запускается с ./.
  • Используйте замену процесса с <( вместо каналов для предотвращения поврежденных каналов, когда процесс отправки завершается.
  • Используйте дескриптор файла между 3 и 9 для передачи данных вместо стандартного входа для предотвращения жадных команд как cat или ssh прихлебывание всего этого.
  • Прежде всего, тест! Я обычно использую это имя файла для тестирования материала, упомянул выше: $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
6
27.01.2020, 21:49

Теги

Похожие вопросы