Остановить расширение подстановочных знаков оболочки?

88

Есть ли способ для скомпилированной программы командной строки сообщить bash или csh, что она не хочет, чтобы какие-либо подстановочные знаки в ее параметрах расширялись?

Например, вам может понадобиться такая команда оболочки, как:

foo *

просто вернуть числовое значение ASCII этого символа.

hotpaw2
источник

Ответы:

119

Нет. Расширение происходит до фактического запуска команды.
Вы можете отключить глобус только перед выполнением команды или указав звездочку.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob
c00kiemon5ter
источник
3
также, если нечего расширять, нет расширения. т.е. с пустым pwd, echo *это просто*
sam boosalis
7
@sam На самом деле это зависит от того, как установлены ваши параметры. Из tldp: «Если совпадающие имена файлов не найдены и опция оболочки nullglobотключена, слово остается без изменений. Если nullglobопция установлена ​​и совпадений не найдено, слово удаляется».
Крис Миддлтон,
спасибо, я должен был сделать оговорку, что это было просто наблюдением, а не каким-либо пониманием.
Sam Boosalis
@ c00kiemon5ter Как отменить set -f? Это так unset -f?
Nam G VU
1
@NamGVUset +f
Ингвар Кристиансен,
62

Хотя верно, что команда сама по себе не может отключить подстановку подстановки, пользователь может указать оболочке Unix не подменять конкретную команду. Обычно это достигается путем редактирования файлов конфигурации оболочки. Предполагая, что команду fooможно найти по пути к команде, в соответствующий файл конфигурации необходимо добавить следующее:

Для оболочек sh, bash и ksh:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Для оболочек csh и tcsh:

alias foo 'set noglob;\foo \!*;unset noglob'

Для оболочки zsh:

alias foo='noglob foo'

Путь к команде использовать не обязательно. Скажем, команда foo хранится в каталоге ~ / bin, тогда приведенное выше будет выглядеть так:

Для оболочек sh, bash и ksh:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Для оболочек csh и tcsh:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Для оболочки zsh:

alias foo='noglob ~/bin/foo'

Все вышеперечисленное было протестировано с использованием Apple OSX 10.9.2. Примечание. При копировании приведенного выше кода будьте осторожны, не удаляя пробелы. Они могут быть значительными.

Обновить:

Пользователь Гейра указал, что в случае оболочки bash

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

можно заменить на

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

что устраняет необходимость в функции foo.

Некоторые веб-сайты, использованные для создания этого документа:

Дэвид Андерсон
источник
3
Это должен был быть принятый ответ, поскольку он доказывает, что действительно можно делать то, что хочет OP. Для некоторых даже более эффективных методов в bash эта ссылка документирует различные варианты: blog.edwards-research.com/2011/05/preventing-globbing
geira
@geira: Иногда ответ принимается до того, как будет опубликован лучший ответ. Я считаю, что это может быть один из таких случаев. Я также считаю, что ответы, отмеченные как наиболее полезные для пользователей, оказываются первыми. Примечание. Я добавил ваши комментарии к своему ответу.
Дэвид Андерсон
@geira, OP хочет, чтобы скомпилированная программа взаимодействовала с оболочкой; ответ о том, что оболочку можно настроить так, чтобы она вела себя по желанию для каждой отдельной команды, является полезным ответом, и я сам согласен с этим, но я вижу возможность не согласиться с тем, полностью ли он соответствует требованиям.
Чарльз Даффи
То, что это можно сделать, не означает, что это нужно делать. Изменение поведения оболочки по сравнению с разумными ожиданиями пользователя для выбранных команд звучит удивительно и, в конечном счете, нежелательно.
tripleee
@tripleee: Было время, когда люди ждали от реле и электронных ламп. Ожидались отверстия в картонных картах и ​​бумажной ленте. Вместо калькуляторов и телефонов люди держали правила слайдов. Полагаю, для вас это было бы желательно. Мне было наплевать на то время. Мне действительно нравится смотреть, что будет дальше.
Дэвид Андерсон
8

Расширение выполняется оболочкой перед запуском вашей программы. Ваша программа не знает, произошло расширение или нет.

   set -o noglob

отключит раскрытие в вызывающей оболочке, но вам придется сделать это до вызова программы.

Альтернативный вариант - процитировать ваши аргументы, например

foo "*"
Брайан Агнью
источник
4
setopt кажется командой, специфичной для zsh. Как сказал другой плакат, для bash вы используете set -o noglobдля отключения подстановочного знака.
Вираван Пурванто,
Сейчас внесены поправки. Спасибо
Брайан Агнью
1

Будьте осторожны: если нет имен, соответствующих маске, bash передает аргумент как есть, без раскрытия!

Доказательство (pa.py - очень простой скрипт, который просто выводит свои аргументы):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']
Лесник
источник
3
Не всегда. set -o nullglobили shopt -s failglob, и это поведение изменится (двумя очень разными способами).
Чарльз Даффи