Как определить функцию Bash, которая может использоваться различными скриптами

13

Я определил bashфункцию в моем ~/.bashrcфайле. Это позволяет мне использовать его в терминалах оболочки. Однако, кажется, что он не существует, когда я вызываю его из скрипта.

Как я могу определить bashфункцию, которая будет использоваться скриптами?

Onturenio
источник
Но мой .bash_profile в основном читает файл .basrc, так что я ожидаю, что результат будет одинаковым, независимо от того, использую я логин или не логин.
Онтуренио
Вы используете /bin/shв линии Шебанга?
Кевин

Ответы:

9

~/.bash_profileи ~/.bashrcне читаются скриптами, а функции не экспортируются по умолчанию. Для этого вы можете использовать export -fтак:

$ cat > script << 'EOF'
#!/bin/bash
foo
EOF
$ chmod a+x script
$ ./script
./script: line 2: foo: command not found
$ foo() { echo "works" ; } 
$ export -f foo
$ ./script
works

export -f fooтакже может быть вызван, ~/.bash_profileчтобы сделать эту функцию доступной для сценариев после входа в систему. Имейте в виду, что export -fэто не портативно.

Лучшим решением было бы использовать файл, содержащий функцию, используя . file. Это гораздо более переносимо и не зависит от конкретной настройки вашей среды.

Крис Даун
источник
почему бы просто не объявить функцию, как function myFunction { ... }в, ~/.bash_profileи вы готовы пойти?
амфибия
Если бы я правильно понял ваш ответ (относительно поиска файла с помощью функции), это означало бы, что мне нужно явно указывать файл в каждом сценарии, что довольно сильно раздражает. Это не намного сложнее, чем просто копировать саму функцию в каждом скрипте. Я бы сохранил несколько строк, конечно, но это все. Тем не менее, exportрешение, кажется, работает правильно. Благодарю.
Онтуренио
@foampile, это именно то, что я сделал и не работает при вызове функции из скрипта.
Онтуренио
1
@ Onurenio: второй метод, предложенный @ chris-down, действительно лучше: 1) Когда кто-то читает скрипт, он знает, что ему нужна какая-то fooфункция из file2) Вы можете лучше контролировать содержимое этого, fileчем быть уверенным, что вызывающая оболочка не изменился fooдо вызова вашего сценария. fileНапример, вы можете добавить проверку безопасности, чтобы убедиться, что он не нарушен. (не легко, но возможно). (ну, вы могли бы также выполнить эти проверки для определенной функции foo ... но вы поняли мой дрейф ^^ Я думаю, что метод 2 чище.) 3) fileбудет содержать только то, что нужно, не больше.
Оливье Дюлак
8

.bashrcчитается только интерактивными оболочками. (На самом деле, это упрощение: bash в этом отношении причудлив. Bash не читает, является .bashrcли он оболочкой входа в систему, интерактивной или нет. И есть исключение даже из исключения: если родительский процесс bash равен rshdили sshd, то bash читает .bashrc, будь то интерактивный или нет.)

Поместите определения вашей функции в файл в известном месте и используйте встроенную .(также записанную source) встроенную функцию для включения этого файла в сценарий.

$ cat ~/lib/bash/my_functions.bash
foo () {

$ cat ~/bin/myscript
#!/bin/bash
. ~/lib/bash/my_functions.bash
foo bar

Если хотите, можете воспользоваться функцией автозагрузки в ksh. Поместите каждое определение функции в файл с тем же именем, что и функция. Перечислите каталоги, содержащие определения функций в FPATHпеременной (список каталогов через двоеточие). Вот грубое приближение ksh, autoloadкоторое фактически загружает функцию сразу, а не по требованию:

autoload () {
  set -- "$(set +f; IFS=:;
            for d in $FPATH; do
              if [ -r "$d/$1" ]; then echo -E "$d/$1"; break; fi;
            done)"
  [[ -n $1 ]] && . "$1"
}
Жиль "ТАК - прекрати быть злым"
источник
+1 для автозагрузки, хотя я рекомендую использовать те, которые идут с bash. Последний поддерживает ленивую загрузку.
Морская звезда
0

Вам нужна функция? Если нет, подумайте о том, чтобы вытянуть логику в отдельный автономный скрипт Bash $PATH. Например, у меня было это в моем ~/.bashrc:

# echo public IP address
alias wanip='dig +short myip.opendns.com @resolver1.opendns.com'

~/binнаходится в моем $PATH, поэтому я создал ~/bin/wanipсо следующим содержанием:

#!/bin/bash

# echo public IP address
dig +short myip.opendns.com @resolver1.opendns.com

И побежал, chmod 0755 ~/bin/wanipчтобы сделать его исполняемым. Теперь я могу выполнить wanipиз других скриптов.

Мне нравится иметь wanipв автономном скрипте Bash. Это напоминает мне, что я хочу, чтобы эта логика была общедоступной (кроме только в моей текущей интерактивной сессии Bash). Скрипт красиво инкапсулирует логику и документацию для одного и того же.

Адам Монсен
источник