В чем разница между ~и без ~в строковой переменной в Bash?

Почему ваш код не работает

Шаблон подстановочных знаков *.aviрасширяется оболочкой, которая запускает findперед запуском find, поэтому его действие зависит от того, есть ли файлы *.aviв текущем каталоге или нет. См. find not recursive when file at top для получения дополнительных пояснений. Чтобы расширить *.aviв подкаталогах,вам нужно будет сделать три вещи по-разному :указать шаблон, чтобы исходная оболочка не расширяла его; организовать запуск дополнительной оболочки в каждом подкаталоге для выполнения подстановочного расширения; и искать каталоги только с помощью команды find, а не любого типа файла.

Кроме того, ваш код вызывает renameдля каждого файла на любом уровне в текущем каталоге, включая сами подкаталоги, через {} +. Итак, renameработает с каталогами, а не только с обычными файлами.

Кроме того, в вашем коде Perl есть синтаксическая ошибка.

Рабочее решение с zsh

autoload -Uz zmv # best in ~/.zshrc

zmv -n '(**/)(*.avi)(#qD^/)' '$1${2//[^a-zA-Z0-9._-]/_}'

^/— выбрать любой тип файла, кроме каталога . Замените на .только для обычных файлов . -nдля работы всухую -. Удаляйте, когда счастливы.

Рабочее решение с findиrename

С вариантами renameна основе perl -и реализацией find, поддерживающей-execdir:

LC_ALL=C find. -depth -name '*[!a-zA-Z0-9._-]*.avi' ! -type d -execdir \
  rename 's/[^a-zA-Z0-9._-]/_/g' {} +

При таком подходе есть несколько предостережений:

  • Это запускает как минимум один renameэкземпляр на каталог, содержащий файлы для переименования (один renameна файл с некоторыми findреализациями/версиями, где -execdir... {} +фактически совпадает с -execdir... {} \;.(zmvзапускает один mvдля каждого файла, но вы можете сделать mvвстроенным с помощью zmodload zsh/files, чтобы ускорить его ).
  • С помощью -execdirfindзапускает команду в каталоге , который содержит эти файлы, и передает команде путь относительно этого каталога. Некоторые findреализации (GNU )добавляют префикс ./к файлам, некоторые — нет. Некоторые варианты renameпринимают опции после выражения Perl, что означает, что если у вас есть файл, имя которого начинается с -, это может вызвать проблемы.
  • мы должны использовать LC_ALL=Cдля -nameдля работы, даже если имена файлов содержат последовательности байтов, которые в противном случае не сформировали бы допустимые символы в локали. renameнаследует это и в любом случае в большинстве вариантов работает только с ASCII. Однако это означает, что он заменит многобайтовые символы -на столько _, сколько байтов содержит символ. Например, он переименует UTF -8 stéphaneв st__phaneвместо st_phane. zshподходит, потому что он преобразует как многобайтовые символы -, так и все байты, которые не могут быть декодированы в символы, в один _символ каждый.
  • в отличие от zsh's zmv, он не будет выполнять проверки работоспособности (например, 2 файла не будут иметь одинаковое имя, например a+b.aviиa@b.avi)до начала переименования. Однако renameне должен перезаписывать существующие файлы.
3
22.10.2018, 09:58
1 ответ

~— это ярлык для вашего домашнего каталога, но только когда он появляется в начале строки вне кавычек . Начало правой -части оператора присваивания является началом строки, поэтому env1=~/Dropbox/.envбудет работать как (или env1=~"/Dropbox/.env"или любое количество вариантов ). Он устанавливает env1в /home/roach/Dropbox/.env. Но env1="~/Dropbox/.env"устанавливает env1в точную строку ~/Dropbox/.env, которая в качестве имени файла выглядит внутри каталога с одним -символьным именем ~в текущем каталоге.

Тильда — это аббревиатура, а не подстановочный знак. $env1вне кавычек расширяет подстановочные знаки в значении env1, но не расширяет тильду, потому что тильда не является подстановочным знаком.

Вы также можете использовать env1="$HOME/Dropbox/.env". Это эквивалентно env1=~/Dropbox/.env. Символ$(доллар )имеет особое значение внутри двойных кавычек (это то же значение, что и вне кавычек ):он начинает подстановку переменной (или команду или арифметическую подстановку ). С другой стороны, символ~(тильда )является обычным символом, если он заключен в кавычки, даже в двойные кавычки.


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

Причина, по которой псевдоним вообще работает во втором скрипте, заключается в том, что dotdrop сама расширяет тильду, когда читает значение конфигурации.

11
27.01.2020, 21:09

Теги

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