Почему 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":

Оба упоминают, что расширение пути происходит до удаления цитаты.

  1. Расширение имени пути (см. Расширение пути) должно выполняться, если только set -f не действует.
  2. Удаление цитаты (см. "Снятие цитаты" ) всегда должно выполняться последним.

Учитывая это, поведение 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. В стандарте говорится

  1. Удаление цитаты (см. "Снятие цитаты" ) всегда должно выполняться последним.

Это означает буквально, как чисто синтаксическое действие для удаления защитных котировок на самом последнем шаге. Семантический смысл цитат будет по-прежнему применяться на более ранних этапах, как указано hek2mgl. (В противном случае, например, такая цитата, как "*", не имела бы никакого эффекта.)

Итак, во-вторых, этот вывод неверен:

Учитывая это, шикарное поведение выглядит правильно, потому что "bar" /* не буквально соответствуют любому пути выше, чем удаление цитаты, поэтому путь расширения не происходит.

Ответ 2

Еще до цитаты удаления оболочка будет обрабатывать некотируемые " как разделители строк не как буквенные символы.

Кроме того, я не могу воспроизвести результаты теста. В обоих случаях bash и posh дали те же результаты для меня.

Ответ 3

Вы можете попробовать с bash --posix (иметь поведение POSIX), и вы увидите, что результат bar/baz.

Дело в том, что расширение пучка "bar" дает bar. См. Раздел 2.13 SCL для получения более подробной информации о шаблоне, соответствующем расширению имени пользователя.