#bash #macos #zsh #glob #oh-my-zsh
#macos #zsh #глобус #о-мой-zsh
Вопрос:
Предположение: допустим, у меня есть подстановочная строковая переменная, которая представляет путь к набору файлов, заканчивающихся на .txt (содержащий пробелы):
a="/hello world/*.txt"
Проблема: я хочу удалить эти файлы в терминале, используя $ rm $:
rm $a
Когда я выполняю приведенную выше команду, я получаю следующую ошибку:
rm: /hello world/*.txt: No such file or directory
То же самое для ниже:
rm "$a"
Или даже если я избегаю пробелов, я все равно получаю ту же ошибку.
Вопрос: Как я могу удалить эти пути в bash на основе заданного подстановочного пути в переменном формате.
Подробная информация:
- Вывод
$- == 569JNRXZghiklms
- ОПЕРАЦИОННАЯ система: Mac OS X 10.15.7
- Я использую zsh
- Вывод моего bash —version:
❯ bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin19) Copyright (C) 2007 Free Software Foundation, Inc.
Комментарии:
1. Добавьте вывод
echo $-
к вашему вопросу (без комментариев).2. Каково фактическое имя файла, который вы хотите удалить?
3. @RamanSailopal Это не файл. Это набор файлов, заканчивающийся на .txt
4. @Cyrus Я обновил вопрос дополнительной информацией
Ответ №1:
Это немного отличается в zsh от других оболочек (например, bash). В большинстве оболочек, если вы расширяете переменную, не заключая ее в двойные кавычки (например rm $a
), значение переменной подвергается как разделению слов (т. Е. Разбивается на несколько «слов»), так и расширению подстановочных знаков. Однако в zsh ни разделение слов, ни расширение подстановочных знаков не выполняются для переменных, даже если они не заключены в двойные кавычки (по крайней мере, по умолчанию).
В вашем случае вам нужно выполнить расширение подстановочных знаков, но не разделение слов (это разбило бы его на два отдельных элемента: «/hello» и «world/*.txt»). В zsh вы можете явно запросить, чтобы расширение подстановочного знака выполнялось с ~
помощью префикса:
rm ${~a}
Вы также можете использовать setopt GLOB_SUBST
, который включает подстановочное расширение для всех последующих расширений переменных (и команд).
Если бы вы использовали bash или какую-либо другую подобную оболочку, это было бы сложнее, потому что у них нет естественного способа расширения подстановочных знаков без разделения слов. Но вы можете изменить способ разделения слов, чтобы он фактически ничего не делал:
saveIFS=$IFS
IFS=
rm $a
IFS=$saveIFS
IFS
это список символов «пробелов», которые обрабатываются как разделители слов; когда это нулевая строка, разделителей нет, поэтому фактического разделения не происходит. Но вы должны быть уверены IFS
, что после этого вернетесь к нормальному состоянию, иначе вы можете получить странные эффекты.
Комментарии:
1. Спасибо за ваш ответ. Я ищу общий способ сделать это. Это часть более крупного фрагмента скрипта, и я хочу распространять его как часть пакета. Это
rm ${~a}
общее решение? Если нет, есть ли у вас какие-либо предложения? Я бы не подумал, что удаление набора файлов будет таким сложным, lol!2. @linker Это зависит от общей картины, но обычно лучший ответ: не хранить шаблоны глобусов в переменных. Часто имеет смысл сохранить некоторые или все фиксированные части в переменных и применять подстановочные части при их использовании (например
rm "$dir"/*."$ext"
), или сразу развернуть подстановочный знак в массив совпадающих файлов (напримерfiles=("/hello world"/*.txt)
, and thenrm "${files[@]}"
), или сочетание обоих (напримерfiles=("$dir"/*."$ext")
). Если вы пишете сценарии на bash, см. BashFAQ #20 (хотя некоторые из них применимы и к zsh).