#bash #function #alias
#bash #функция #псевдоним
Вопрос:
Я знаю, что могу запустить «оригинальную» команду (не псевдоним), используя либо
или ""
:
ls
"ls"
Однако это не работает для функций. Также это требует, чтобы я каждый раз использовал этот синтаксис.
Возможно ли в исходном скрипте отключить все функции / псевдонимы из родительского процесса (того, который запускает мой скрипт)? Т.е. Если у пользователя в их терминале определены некоторые функции псевдонимов, я хочу, чтобы они были отключены в моем скрипте (но, конечно, я все еще хочу иметь возможность определять и использоватьсобственные псевдонимы / функции).
Комментарии:
1. Псевдонимы и функции из родительского процесса не должны иметь никакого эффекта в вашем сценарии, если вы не экспортируете функции или не создаете исходный сценарий.
2. Вы правы, я забыл упомянуть, что это исходный скрипт, мой плохой. Я отредактировал вопрос.
3. Вы могли бы префиксить все с
builtin
помощью илиcommand
(см.help builtin
Иhelp command
), но я знаю, что я не могу придумать способ сделать это автоматически в исходном скрипте без изменения «родительской» среды или потери преимуществ исходного скрипта.4. Разумное решение, вероятно, заключается в том, чтобы не использовать исходный код вашего скрипта, а вместо этого заставить его печатать что-то, чему вызывающий должен доверять и
eval
.5. @Socowi Сделайте свой комментарий ответом — если никто не придумает ничего лучшего, я приму это. Также, пожалуйста, объясните разницу между
builtin
иcommand
в этом случае, если это возможно.
Ответ №1:
Типы команд в Bash
Bash знает разные типы команд, которые могут затенять друг друга. Приоритет этих типов:
- Псевдонимы
может быть определен пользователем с помощьюalias cmd=...
- функции
может быть определен пользователем с помощьюcmd() { ... }
- встроенные
непосредственно реализуются в bash и не могут быть изменены.help
иenable
перечислите все встроенные модули. - Исполняемые файлы в
$PATH
Это означает, что если вы вводите cmd arg1 arg2 ...
, вы используете псевдоним cmd
, если он определен, в противном случае вы используете функцию cmd
, если она определена, в противном случае вы используете встроенный cmd
, если он встроенный, в противном случае вы используете первый исполняемый cmd
файл из каталогов, $PATH
если он есть, в противном случае вы получите ошибку -bash: cmd command not found
.
Какой из этих случаев применяется cmd
, можно проверить с помощью type -a cmd
.
Управление приоритетом вручную
Bash позволяет вам определять, какой тип выбрать, используя кавычки и встроенные command
функции и builtin
.
cmd
подавляет псевдонимы
, использует функции, встроенные модули, исполняемые файлыcommand cmd
подавляет псевдонимы и функции
, использует встроенные и исполняемые файлыbuiltin cmd
подавляет псевдонимы, функции и исполняемые
файлы, использует только встроенныеenable -n cmd
полностью отключает встроенноеcmd
, так что впоследствии используются только
псевдонимы, функции и исполняемые файлыenv cmd
не встроенный bash, поэтому он на самом деле ничего не подавляет, а
использует только исполняемые файлы
Примеры
Затенение совершенно нормально. Например, bash имеет свой собственный встроенный echo
, но ваша система также имеет /bin/echo
. Обе реализации могут отличаться. Например, мой echo
из bash 5 поддерживает uXXXX
, а мой echo
из GNU coreutils 8.3 — нет. Возможность таких различий становится еще более очевидной, если вы добавляете свои собственные реализации, используя псевдонимы и функции. Вот пример интерактивного сеанса bash ( $
это подсказка):
$ echo() { printf "function echo: %sn" "$*"; }
$ alias echo='printf "alias echo: %s %s %sn"'
$ type -a echo
echo is aliased to `printf "alias echo: %s %s %sn"'
echo is a function
echo ()
{
printf "function echo: %sn" "$*"
}
echo is a shell builtin
echo is /bin/echo
$ echo -e 'u2261'
alias echo: -e u2261
$ echo -e 'u2261'
function echo: -e u2261
# use the built-in (or executable file if there was no such built-in)
$ command echo -e 'u2261'
≡
$ builtin echo -e 'u2261'
≡
# use the executable /bin/echo
$ env echo -e 'u2261'
u2261
$ enable -n echo
# use the executable /bin/echo (`command` is needed to skip the alias and function)
$ command echo -e 'u2261'
u2261
Отвечая на ваш вопрос
К сожалению, я не знаю о чем-то вроде enable
постоянного отключения поиска псевдонимов и функций. Вы могли бы попробовать некоторые хаки, такие как резервное копирование всех псевдонимов и функций, выполнение unset -f
и unalias
для них и восстановление их в конце. Однако unset
может произойти сбой для функций только для чтения. Лучшим способом было бы использовать bash -c '... functions and aliases have no effect here ...'
для тех частей, где вам действительно не нужны преимущества source
. Для других частей префикс все с command
.
Пожалуйста, обратите внимание: вызывающий абонент, который создает ваш скрипт, может даже отключить или затенить command
, builtin
, и так далее — поэтому вы никогда не можете быть уверены, что на самом деле используете ожидаемые команды. Даже запись /usr/bin/env executable
или /path/to/the/executable
не помогает, поскольку функция может иметь имя, и $PATH
/ или файловая система может быть изменена. Однако это не должно вас беспокоить. Тот, кто создает ваш скрипт, должен нести ответственность за обеспечение правильной среды.
Комментарии:
1. Отличный ответ! Однако в документации POSIX
env
говорится, что , если аргумент toenv
является встроенным, результаты не определены. Поэтому может быть неверно говоритьenv
«использует только исполняемые файлы».2. Спасибо, какая странная маленькая деталь. Я оставляю это из этого ответа, чтобы упростить его. Но благодаря вашему комментарию информация доступна для всех.
Ответ №2:
Редактировать: этот ответ может больше не иметь значения, поскольку вы отредактировали вопрос, чтобы уточнить, что сценарий является исходным кодом, а не выполняется в подоболочке.
Это происходит по умолчанию. Доказательство:
$ function x() { echo 'hi'; }
$ x
hi
$ bash
# We are now in a subshell.
$ x
bash: x: command not found
Функции часто определяются в одном из файлов запуска оболочки: .bashrc
, .profile
или .bash_profile
. Какие из них являются исходными, зависит от того, является ли оболочка оболочкой входа и / или интерактивной оболочкой. Оболочка, которая вызывается для выполнения сценария оболочки, не является ни оболочкой входа, ни интерактивной оболочкой, и в этом случае ни один из этих файлов не является исходным кодом.
Ответ №3:
РЕДАКТИРОВАТЬ: я должен прочитать более внимательно, поскольку вы не хотите создавать исходный сценарий, но должны быть получены, следующее для обратного пути:
Функции
Если вы исходите из своего родительского скрипта в начале, вы можете просто перебирать определенные функции и отменять их.
declare -F
будут перечислены все определенные функции, но в формате declare -f functioname
, поэтому вам нужно получить только имя:
IFS=$'n'
for f in $(declare -F|cut -d ' ' -f 3); do
unset -f $f
done
Псевдонимы
Псевдоним не должен быть указан, насколько я помню, но если они есть, вы можете сделать
unalias -a
чтобы отменить их все.