source some_file
some_file:
doit ()
{
echo doit
}
export TEST=true
如果我提供some_file,则函数“ doit”和变量TEST在命令行上可用。但是运行以下脚本:
script.sh:
#/bin/sh
echo $TEST
doit test2
将返回TEST的值,但会生成有关未知函数的错误“ doit”。
我也可以“导出”该功能吗,还是必须在script.sh中提供some_file才能在该位置使用该功能?
#1 楼
在Bash中,您可以使用export -f function_name
将函数定义导出到子外壳中,例如,您可以尝试以下简单示例:
./script1
:#!/bin/bash
myfun() {
echo "Hello!"
}
export -f myfun
./script2
./script2
:#!/bin/bash
myfun
然后,如果您调用
./script1
,您将看到输出Hello!。#2 楼
使用export -f
“导出”功能会使用功能主体创建一个环境变量。考虑以下示例:$ fn(){ echo \'\"\ \ $; }
$ export -f fn
$ sh -c printenv\ fn
() { echo \'\"\ \ $
}
这意味着只有外壳程序(仅Bash?)才能接受该功能。您还可以自行设置函数,因为Bash仅将以
() {
开头的envvars作为函数:$ fn2='() { echo Hi;}' sh -c fn2
Hi
$ fn3='() {' sh -c :
sh: fn3: line 1: syntax error: unexpected end of file
sh: error importing function definition for `fn3'
如果需要通过SSH“导出”此变量,则可以确实需要将该函数作为字符串。可以使用内置的
-p
的功能(-f
)的打印选项(declare
)完成此操作:$ declare -pf fn
fn ()
{
echo \'\"\ \ $
}
如果您有更复杂的代码,这将非常有用需要通过SSH执行。请考虑以下虚拟脚本:
#!/bin/bash
remote_main() {
local dest="$HOME/destination"
tar xzv -C "$dest"
chgrp -R www-data "$dest"
# Ensure that newly written files have the 'www-data' group too
find "$dest" -type d -exec chmod g+s {} \;
}
tar cz files/ | ssh user@host "$(declare -pf remote_main); remote_main"
评论
fn2 ='(){echo Hi;}'sh -c fn2对我不起作用。在sh为bash v5.0.7的arch linux上,我得到sh:fn2:找不到命令。在sh为破折号v0.2.3的Ubuntu上,我得到sh:1:fn2:找不到。您使用了哪个sh shell?
–索科维
19年7月2日在16:03
我认为您的回答是错误的。 f(){echo a;};出口-f f;回显“ $ f”; sh -c'printenv f; echo“ $ f”'不为我打印任何内容,因此显然f不会作为纯字符串导出。我测试了上述两种组合。
–索科维
19年7月2日在16:16
即使将函数导出为字符串,为什么还要sh将该字符串作为函数执行?在您的示例中,fn2 ='(){echo Hi;}'sh -c fn2给sh的命令fn2实际上是字符串“ fn2”。 sh应该在其PATH中搜索这样的命令,但不应该查看是否存在变量$ fn2,扩展该变量并以函数形式执行其值–在我看来,这是一个重大的安全问题。编辑:我想就是这样!您所显示的行为是被称为ShellShock / Bashdoor的安全漏洞吗?
–索科维
19年7月2日在16:26
在Bash 5.0.7(Arch Linux)中,前缀似乎是前缀。这可能是为了响应ShellShock。范例:fn(){echo foo; };出口-f fn; env | grep foo输出BASH_FUNC_fn %% =(){echo foo
– Lekensteyn
19年7月2日在22:04
#3 楼
以@Lekensteyn的答案为基础...如果使用
declare -pf
,它将在当前Shell中将所有先前定义的函数输出到STDOUT。 此时,您可以将STDOUT重定向到所需的位置,并有效地将先前定义的功能填充到所需的位置。
以下答案会将其填充到变量中。然后,我们回显该变量以及要运行到作为新用户生成的新shell中的函数的调用。我们通过将
sudo
与-u
(也称为user
)开关一起使用并简单地运行Bash(它将接收管道STDOUT作为要运行的输入)来执行此操作。 正如我们所知,我们正在从Bash shell过渡到Bash shell,我们知道Bash将正确解释以前的Shell定义的函数。只要我们在一个相同版本的Bash shell到相同版本的新Bash shell之间移动,语法就可以了。
YMMV,如果您在不同的Shell之间或在可能具有不同版本的Bash的系统之间移动。
#!/bin/bash
foo() {
echo "hello from `whoami`"
}
FUNCTIONS=`declare -pf`; echo "$FUNCTIONS ; foo" | sudo -u otheruser bash
# $./test.sh
# hello from otheruser
#4 楼
您不能导出函数,而不是按照描述的方式导出。该外壳程序只会在交互式外壳程序开始时加载~/.bashrc
文件(在bash联机帮助页中搜索“ Invocation”)。您可以做的是创建“ library”,该文件库在您启动时就已加载程序:
source "$HOME/lib/somefile"
,然后将非交互功能和设置放在此处。
评论
因此,我必须使用“ login”参数启动子shell(以解析〜/ .profile)或源该文件。
–指甲
2011年10月17日19:11
仔细观察一下,在非交互式shell上,可以将BASH_ENV环境变量设置为您已经拥有的some_file,它将被调用。找出答案很容易:echo echo foobar> / tmp / foobar; BASH_ENV = / tmp / foobar $ SHELL -c:
–Arcege
2011-10-17 19:20
由于某种原因,这对我不起作用。我已经写了很多shell脚本,包括库脚本。出于某种原因,即使我的.profile成功地获取了我的.bashrc(我通过回显将源的变量进行测试)。我只是无法弄清楚为什么找不到我的函数,但是却可以找到要回显的变量。
– Ungeheuer
20 Dec 25'2:05
#5 楼
eval "$(declare -F | sed -e 's/-f /-fx /')"
将导出所有函数。在启动脚本中的交互式外壳程序之前,我需要执行很多操作,以使我能够在使用脚本的函数和变量的同时在脚本上下文中进行调试和工作。
示例:
eval "$(declare -F | sed -e 's/-f /-fx /')"
export SOME IMPORTANT VARIABLES AND PASSWORDS
bash -i
#6 楼
函数不会导出到子流程。这就是为什么存在名为.kshrc或.bashrc的文件的原因:定义也可以在子shell中使用的函数。如果运行脚本,则通常不提供。* shrc脚本。您必须像
. ~/.kshrc
中那样显式地编写代码。评论
因此,在我的情况下,〜root / .bashrc是一个选项,因为脚本是作为root运行的。感谢您的提示。
–指甲
11-10-17在19:06
如果使用。* shrc文件,请确保它们不强制进行交互行为(如愚蠢的别名rm = rm -i)
–ktf
2011-10-18 8:50
#7 楼
好吧,我是Linux的新手,但是您可以尝试一下。在某个文件中,我们称其为“ tmp / general”,即表示您要构建函数:func1(){
echo "func from general"
}
在您的shell脚本中添加:
. /tmp/general
并运行:
func1
您将在屏幕上看到:
func from general
。#8 楼
declare -x -f NAME
更多信息
-f restrict action or display to function names and definitions -x to make NAMEs export
评论
总结以下答案(enzotib是正确的,假设您可以使用bash,如问题所示):将#!/ bin / sh更改为#!/ bin / bash,然后在doit(){...}之后仅导出-f doit仅作记录:此解决方案通常在您也使用#!/ bin / sh时也可以使用,但是最好使用#!/ bin / bash,这样可以避免默认的shell不是bash时出现问题。 >
stackoverflow.com/questions/1885871/…