Я читал, что рекомендуется заключать в двойные кавычки все расширения переменных в Bash. Я также читал, что нельзя использовать глобус оболочки (подстановочный знак (*)) сразу после раскрытия переменной в двойных кавычках. Эти ситуации конфликтуют, когда кто-то хочет использовать значение шаблона регулярного выражения, расширенного из переменной.

Причина, по которой я иногда хотел бы объединить регулярное выражение с подстановочным знаком, заключается в том, чтобы сделать мое регулярное выражение минимальным, аккуратным, в моем личном вкусе.

Моя конкретная проблема

Я загрузил phpmyadmin в корневой каталог моего документа и разархивировал его, но мне не удалось переименовать его с помощью mv по шаблону регулярного выражения, который я поместил в переменную и который доступен при расширении его переменной. Вот точный след:

userName@compName:/var/www/html# ll
total 11336
drwxr-xr-x  3 root root     4096 Feb 14 07:04 ./
drwxr-xr-x  3 root root     4096 Feb 14 06:56 ../
-rw-r--r--  1 root root      612 Feb 14 06:57 index.nginx-debian.html
drwxr-xr-x 12 root root     4096 Dec 23 08:50 phpMyAdmin-4.7.7-all-languages/
-rw-r--r--  1 root root 11589684 Dec 23 14:08 phpMyAdmin-latest-all-languages.zip
userName@compName:/var/www/html# echo $pma
[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]
userName@compName:/var/www/html# mv "$pma"*/ phpmyadmin/
mv: cannot stat '[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]*/': No such file or directory

Если я раскавычу расширение переменной до ${pma}, я действительно смогу объединить расширение переменной и регулярное выражение, как в ${pma}*, но для меня важно следовать передовой практике без исключений, если я могу.

Мой вопрос

Как я могу сохранить расширение переменной в двойных кавычках, но при этом использовать извлеченное значение с подстановочным знаком?

-3
Jeff Schaller 14 Фев 2018 в 13:48
 – 
muru
14 Фев 2018 в 10:35
Почему бы просто не извлечь и сохранить имя файла из URL-адреса при его загрузке? Кстати, регулярное выражение, вероятно, никогда не понадобится - крайне маловероятно, что часть phpMyAdmin имени файла когда-либо изменит какие-либо буквы из верхнего регистра в нижний или наоборот.
 – 
cas
14 Фев 2018 в 11:25
Кроме того, похоже, вы используете Debian (догадываясь по имени файла index.nginx-debian.html), почему бы просто не использовать пакет phpmyadmin в Debian? Необходимая литература: wiki.debian.org/DontBreakDebian
 – 
cas
14 Фев 2018 в 11:30
1
@muru: Что вы имеете в виду, говоря, что «шарики оболочки не являются подстановочными знаками»? Я использую эти термины взаимозаменяемо, как и Жиль< /a>, Стефан Шазела, Джефф Шаллер , наша wildcards теговая вики, …(продолжение)
 – 
Scott
19 Фев 2018 в 00:18
1
Конечно, не помогает то, что мой предыдущий комментарий со ссылкой на другой пост U&L, в котором говорилось о регулярных выражениях и глобах, был удален. Хотелось бы, чтобы моды удаляли все комментарии в беседе вместо этой разрозненной чепухи.
 – 
muru
19 Фев 2018 в 03:01

2 ответа

Лучший ответ

Шаблон подстановки имен файлов, хранящийся в переменной, не будет подставлять имена файлов, если они заключены в двойные кавычки. Именно двойные кавычки предотвращают подстановку имен файлов, а не подстановочный знак * в конце или комбинация кавычек и *.

Мы часто советуем пользователям на сайте «заключить свои переменные в кавычки», и мы делаем это, потому что значения переменных без кавычек подвергаются разбиению на слова и объединению имен файлов, а это обычно не то, что нужно. Например, пароль может быть [hello] world* и в командной строке, содержащей -p $password, что будет делать «интересные» вещи в зависимости от того, какие файлы присутствуют в текущем каталоге (и это может вообще не работать из-за в космос). См. также вопрос "Безопасность последствия забывания заключить переменную в кавычки в оболочках bash/POSIX"

То, что вы хотите сделать здесь, противоположно тому, чего мы обычно избегаем, а именно вызову подстановки имени файла с использованием шаблона подстановки имени файла в вашей переменной.

Если вы действительно не можете полагаться на то, что имя извлеченного каталога останется стабильным, лучшим (как в «более чистом») решением, возможно, будет убедиться, что это единственное имя во временном каталоге. , а затем просто используйте *, чтобы переместить его на место (возможно, изменив его имя в процессе, чтобы вы точно знали, как он называется).

Это лучше, чем простое удаление кавычек вокруг вашей переменной, так как шаблон подстановки имени файла может соответствовать другим именам, кроме одного, которое вы ожидаете, в зависимости от того, какие другие вещи доступны в каталоге.

Это вариант моего ответа на ваш предыдущий вопрос:

#!/bin/sh -ex

destdir="/var/www/html/phpmyadmin"

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT    # remove temporary directory on termination

wget -O "$tmpdir/archive.zip" \
    "https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.zip"

cd "$tmpdir" && {
    unzip archive.zip
    rm -f archive.zip

    # The only thing in the current (temporary) directory now is the
    # directory with the unpacked zip file.

    mkdir -p "$destdir"
    mv ./* "$destdir"/phpmyAdmin
} 

Вышеизложенное можно разделить на пять шагов:

  1. Создайте пустой каталог (и измените на него текущий рабочий каталог).
  2. Забрать архив.
  3. Распакуйте архив.
  4. Удалить архив.
  5. Теперь измените имя одинокой папки в пустом каталоге.
6
Kusalananda 14 Фев 2018 в 17:38
Это угрюмо отвечает на вопрос, но я просто хочу сказать, что я нахожу предложение What you want to do here is the opposite of what we usually want to avoid, namely accidentally invoking file name globbing. немного запутанным, потому что ему не предшествует краткое определение того, чего мы обычно хотим избежать (я полагаю, ошибочно подстановочные переменные). Я думаю, что это должно быть немного изменено. Кроме того, возможно, стоит упомянуть $x или ${x} в качестве исключительных альтернатив.
 – 
user9303970
14 Фев 2018 в 17:29
1
Согласованный. Я добавил текст.
 – 
Kusalananda
14 Фев 2018 в 17:39

Как я могу сохранить расширение переменной в двойных кавычках, но при этом использовать извлеченное значение с подстановочным знаком?

Вы не могли1, и не хотите; ваша команда прекрасно работает без них (и я уверен, что это было указано и в одном из ранее удаленных вариантов этого вопроса).

$ mkdir phpMyAdmin-4.7.7-all-languages
$ pma=[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]
$ echo $pma
[pP][hH][pP][mM][yY][aA][dD][mM][iI][nN]
$ echo $pma*/
phpMyAdmin-4.7.7-all-languages/
$ mv $pma*/ phpmyadmin
$ ls
phpmyadmin

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

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


Помимо этого, это:

Я также понял, что нельзя использовать глобус оболочки (подстановочный знак (*)) сразу после раскрытия переменной в двойных кавычках.

Это не правда.

$ tmp=php
$ echo "$tmp"*
phpmyadmin

1 Вы могли использовать eval, но это было бы настолько бессмысленно, что я не буду продолжать это дальше.

0
user9303970 14 Фев 2018 в 11:34