Почему posh не выполняет расширение пути, когда часть пути указана в двойных кавычках?
Рассмотрим следующую простую оболочку script:
rm -rf bar \"bar\"
mkdir -p bar
touch bar/baz
echo "bar"/*
Я получаю ожидаемый результат с bash, ksh, zsh и тире, но я не получаю
это с шиком:
[email protected]:~$ bash foo.sh
bar/baz
[email protected]:~$ ksh foo.sh
bar/baz
[email protected]:~$ zsh foo.sh
bar/baz
[email protected]:~$ dash foo.sh
bar/baz
[email protected]:~$ posh foo.sh
bar/*
Я пытаюсь понять, правильно ли поведение posh соответствует стандарту POSIX или если оно является ошибкой.
Соответствующий раздел в документах POSIX выглядит как "2.6 Word Expansion":
Оба упоминают, что расширение пути происходит до удаления цитаты.
- Расширение имени пути (см. Расширение пути) должно выполняться, если только
set -f
не действует. - Удаление цитаты (см. "Снятие цитаты" ) всегда должно выполняться последним.
Учитывая это, поведение posh выглядит правильно, потому что "bar"/*
буквально не соответствует любому пути выше, чем удаление цитаты, поэтому расширение пути не происходит.
Итак, это заставило меня подозревать, что если бы существовал каталог, буквально названный "bar"
, т.е. кавычки были частью имени каталога, то posh соответствовал бы ему. Но следующий измененный script показывает, что это неверно.
rm -rf bar \"bar\"
mkdir -p \"bar\"
touch \"bar\"/baz
echo "bar"/*
Вот результат:
[email protected]:~$ bash foo2.sh
bar/*
[email protected]:~$ ksh foo2.sh
bar/*
[email protected]:~$ zsh foo2.sh
foo2.sh:3: no matches found: bar/*
[email protected]:~$ dash foo2.sh
bar/*
[email protected]:~$ posh foo2.sh
bar/*
Таким образом, шаблон "bar"/*
в posh не соответствует ни пути bar/baz
, ни пути "bar"/baz
. Что это значит? Является ли поведение posh ошибкой или функцией?
Вот информация о версии, если она поможет вам:
[email protected]:~$ cat /etc/debian_version
8.3
susam[email protected]:~$ dpkg -l bash ksh zsh dash posh
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-===========================-==================-==================-============================================================
ii bash 4.3-11+b1 amd64 GNU Bourne Again SHell
ii dash 0.5.7-4+b1 amd64 POSIX-compliant shell
ii ksh 93u+20120801-1 amd64 Real, AT&T version of the Korn shell
ii posh 0.12.3 amd64 Policy-compliant Ordinary SHell
ii zsh 5.0.7-5 amd64 shell with lots of features
Ответы
Ответ 1
Это ошибка в posh
- см. ошибку # 636601. Он по-прежнему открыт с posh
версией 0.12.6.
Прикрепленный к обсуждение этой ошибки вы найдете patch. При применении этого параметра posh
ведет себя аналогично bash
(поэтому в вашем первом примере echo "bar"/*
дает bar/baz
).
Кроме того, поведение bash
(и исправлено posh
) соответствует POSIX. В стандарте говорится
- Удаление цитаты (см. "Снятие цитаты" ) всегда должно выполняться последним.
Это означает буквально, как чисто синтаксическое действие для удаления защитных котировок на самом последнем шаге. Семантический смысл цитат будет по-прежнему применяться на более ранних этапах, как указано hek2mgl. (В противном случае, например, такая цитата, как "*"
, не имела бы никакого эффекта.)
Итак, во-вторых, этот вывод неверен:
Учитывая это, шикарное поведение выглядит правильно, потому что "bar" /* не буквально соответствуют любому пути выше, чем удаление цитаты, поэтому путь расширения не происходит.
Ответ 2
Еще до цитаты удаления оболочка будет обрабатывать некотируемые "
как разделители строк не как буквенные символы.
Кроме того, я не могу воспроизвести результаты теста. В обоих случаях bash и posh дали те же результаты для меня.
Ответ 3
Вы можете попробовать с bash --posix
(иметь поведение POSIX), и вы увидите, что результат bar/baz
.
Дело в том, что расширение пучка "bar" дает bar
. См. Раздел 2.13 SCL для получения более подробной информации о шаблоне, соответствующем расширению имени пользователя.