GNU находит и маскирует {} для некоторых оболочек - что?

34

Страница man для GNU find содержит следующее:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

Это от человека до find(GNU findutils) 4.4.2.

Теперь я проверил это с помощью bash и dash, и оба не должны {}маскироваться. Вот простой тест:

find /etc -name "hosts" -exec md5sum {} \; 

Есть ли оболочка, для которой мне действительно нужно маскировать брекеты? Обратите внимание, что это не зависит от того, содержит ли найденный файл пробел (вызывается из bash):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

Это изменяется, если найденный файл передается в подоболочку:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

которая может быть решена путем:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

в отличие от:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

но это не то, о чем идет речь на странице руководства, не так ли? Так какая оболочка относится {}по-другому?

неизвестный пользователь
источник
@Volker Siegel: Ваше редактирование могло произойти с добрыми намерениями, но я проверил мое текущее руководство по поиску, и ваши исправления неверны. Вы также упустили возможность обобщить ваши изменения, что является плохой привычкой, поэтому я откатил ваши изменения. Извини, парень.
пользователь неизвестен
О, спасибо за откат, если он что-то сломал. Я помнил, что текстовый компилятор, который генерирует формат man-страницы, используемый для генерации этих «типографских кавычек» как артефакт определения рендеринга. Он также может отображать в TeX для идеального форматирования распечатки. Я заметил кавычки, потому что они перепутали подсветку синтаксиса. Я предположил, что необычная первая кавычка неверна при использовании в коде, и все еще предполагаю это. Обратите внимание, что эти два изменения были в тексте описания, а не в коде. Поэтому, если мы рассматриваем их как типографику - эстетическое изображение - они правы.
Фолькер Сигел
Похоже, что при выводе информации, одна и та же цитата используется с обеих сторон. Нет никаких сомнений в том, что мое изменение отличало его от оригинала, вы правы. Но вызвало ли это какие-либо проблемы? (Я считаю, что первая цитата - ошибка в определении рендеринга человека, насколько я знаю, это единственный случай типографики.)
Volker Siegel
Я только что проверил: `{} 'не работает в командной строке. Это технически правильно, но мне не нравится, что ничего не подозревающий пользователь получает странную ошибку, когда пытается скопировать и вставить ее.
Фолькер Сигел
@VolkerSiegel: Это текст в прозаической форме, а не код, так что пользователь должен скопировать и вставить здесь? И это цитата из справочной страницы за 2011 год. Я не вижу никакого смысла исправлять отрывок, чтобы потом указать, почему я внес исправления в справочную страницу. Тема достаточно сложная. Если бы это был ваш вопрос, я бы не пытался вас убедить, точно процитировать справочную страницу, но на мой вопрос я не в настроении идти на компромисс. Цитирование есть цитирование.
пользователь неизвестен

Ответы:

26

Резюме : если когда-либо существовала расширенная оболочка {}, то это действительно устаревшая версия.

В оболочке Bourne и в POSIX-совместимых оболочках фигурные скобки ( {и }) являются обычными символами (в отличие от (и )которые являются разделителями слов, такими как ;и &, и [и ]которые являются символами слияния). Следующие строки должны быть напечатаны буквально:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

Слово, состоящее из одной фигурной скобки, является зарезервированным словом , которое является специальным, только если оно является первым словом команды.

Ksh реализует расширение скобок как несовместимое расширение оболочки Bourne. Это можно отключить с помощью set +B. Bash подражает ksh в этом отношении. Zsh также реализует расширение скобок; там его можно отключить с помощью set +Iили setopt ignore_bracesили emulate sh. Ни одна из этих оболочек {}ни в коем случае не расширяется , даже если это подстрока слова (например foo{}bar), из-за обычного использования в аргументах findи xargs.

Single Unix v2 отмечает, что

В некоторых исторических системах фигурные скобки рассматриваются как управляющие операторы. Чтобы помочь в будущих действиях по стандартизации, переносимые приложения должны избегать использования не заключенных в кавычки скобок для представления самих символов. Вполне возможно, что будущая версия стандарта ИСО / МЭК 9945-2: 1993 может потребовать этого {и }рассматриваться отдельно как операторы управления, хотя токен {}, вероятно, будет исключением из этого особого случая из-за часто используемой find {}конструкции.

Эта заметка была исключена в последующих версиях стандарта; что примерыfind имеют некотируемые использования {}, как это делают примеры дляxargs . Возможно, там были исторические оболочки Борна, где их {}нужно было процитировать, но они уже были бы действительно устаревшими системами.

Реализации CSH у меня есть под рукой (OpenBSD 4.7, BSD CSH на Debian , Tcsh) все расширения {foo}до , fooно оставить в {}покое.

Жиль "ТАК - прекрати быть злым"
источник
1
@geekosaur: только небольшая часть уценки работает в комментариях . Я не знаю, что ты пытаешься сказать. Если речь идет о расширении скобок ksh et al, прочитайте мой абзац, начинающийся с «Ksh реализует расширение скобок как несовместимое расширение».
Жиль "ТАК - перестань быть злым"
2
Это было bash(см. $BASH_VERSION). Расширение скобок очень живое и здоровое.
geekosaur
2
Это было главное. {}Синтаксис возник в csh, но {}расширен в пустую строку. Новые оболочки признают, что это бессмысленно, но есть еще старые csh.
geekosaur
1
@geekosaur: Можете ли вы сказать, какая конкретная csh-версия для какой конкретной платформы? Я бы предпочел проверить это сам (если это возможно на linux) или быть уверенным, что человек сам это проверяет.
пользователь неизвестен
1
@geekosaur, {}fooрасширится до foo, но {}расширится до {}(за исключением случаев, когда внутри запятых, но цитирование не поможет) и было задокументировано как таковое. Я проверил это для csh из 2BSD (первый выпуск), 2.79BSD, 2.8BSD и 2.11BSD.
Стефан Шазелас
12

{}Нужно быть указаны в версиях fishоболочки До 3.0.0.

$ fish -c 'echo find -exec {} \;'
find -exec  ;

А в оболочке rc (тоже akangaна основе rc, но не es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Вероятно, это не те оболочки, о которых авторы этой GNU считают документацией, когда они писали этот текст с тех пор, как он fishбыл впервые выпущен в 2005 году (хотя этот текст или что-то подобное уже существовало в 1994 году) и rcизначально не был оболочкой Unix.

Есть некоторые слухи о некоторых версиях csh(оболочка, которая ввела расширение скобки), требующих этого. Но трудно отдать должное этим, так как первый релиз cshв 2BSD этого не сделал. Вот как тестируется в эмуляторе PDP11:

# echo find -exec {} \;
find -exec {} ;

И справочная страница из 2BSD cshчетко гласит :

В особом случае `{',`}' и `{} 'передаются без помех.

Поэтому мне было бы очень странно, если бы последующая версия csh или tcsh позже это сломала.

В некоторых версиях можно было бы обойти некоторые ошибки. Все еще с этим 2BSD csh (то же самое в 2.79BSD, 2.8BSD, 2.11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

Цитирование не помогает, хотя:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

Вы можете процитировать всю команду подстановки:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

Но это передает один аргумент этому внешнему эхо.

В cshили tcsh, вы должны указать, {}когда не по отдельности, как в:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(хотя этот вид findиспользования не переносим, ​​так как некоторые findрасширяются только {}сами по себе).

Стефан Шазелас
источник
1

Одним словом csh. bashи другие современные оболочки понимают, что пользователь, вероятно, не просит расширения с нулевой скобкой. (Современный cshна самом деле tcshи может также обрабатывать {}разумно сейчас.)

geekosaur
источник
Приятно слышать, но я прошу об обратном, оболочка, с которой не справляются разумно.
пользователь неизвестен
Вы предполагаете, что кто-то зайдет и вытащит ссылку на информационную страницу о дополнительных цитатах только потому, что все системы Linux имеют более новую версию csh. Не все используют утилиты GNU в Linux; на самом деле их довольно часто устанавливают на старых коммерческих системах Unix, в которых ограничено количество связанных команд. (Замена cshв этих системах менее вероятна, потому что системные скрипты могут полагаться на индивидуальные особенности оригинала csh, и даже если все пользователи были настроены на использование более новой версии csh, rootпочти наверняка потребуется остаться в комплекте версии.)
geekosaur
2
Нет. Я спорю с парнем, который говорит, что в нашей вики мы должны дать совет использовать "{}" все время, потому что на странице руководства так сказано. И теперь я хотел бы знать, есть ли оболочка, которой я не пользуюсь, например ksh, zsh, tcsh, csh или XYZsh, которую я не знаю, для которой это утверждение верно, или могу ли я честно предположить, что нет Если есть оболочки для разных Unix-систем, которым требуется "{}", это было бы хорошим объяснением того, почему предложение все еще находится на странице руководства, но не подходит как совет для начинающих в Linux.
пользователь неизвестен
Теперь я задаюсь вопросом pdksh, правильно ли поступает ... хотя правильный ответ на этот вопрос , вероятно, "настоящий ksh- это FOSS в наши дни".
geekosaur
4
Pdksh, как и mksh, ksh93, bash и zsh, расширяет фигурные скобки только при наличии запятой между ними (или ..для ksh93, bash и zsh). Только (т) CSH расширяется {foo}до foo, и даже она оставляет в {}покое (по крайней мере , на недавнем BSD - х).
Жиль "ТАК - перестань быть злым"