Как удалить набор файлов, используя заданную строку, содержащую подстановочный путь в bash / zsh?

#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 then rm "${files[@]}" ), или сочетание обоих (например files=("$dir"/*."$ext") ). Если вы пишете сценарии на bash, см. BashFAQ #20 (хотя некоторые из них применимы и к zsh).