本问题已经有最佳答案,请猛点这里访问。
我需要一个bash函数来将动态构造的字符串返回给调用者空间。
即
makeName()
{
echo"Enter Ext:"
read ext
return"$fileName.$1.$ext.log"
}
echo -n"Enter fileName:"
read fileName
name1=makeName"type1"
name2=makfName"type2"
因此,我可以获得具有相同基本文件名的两个不同文件名。
我尝试这样做
#echo $(makeName"type1")
但是,此代码没有任何原因或错误地被删除。 我希望它也可以通过该过程接受某种I / O。 那没有发生。
bash所使用的return语句用于返回一个数值,作为状态代码,以由调用函数通过$?进行检索。您不能返回字符串。也可以看看
从Bash函数返回值
如何从Bash函数返回字符串值
您可以使用@konsolebox建议的特殊全局变量,也可以使用echo函数内部的返回值,并在调用函数时使用命令替换:
makeName()
{
echo"$fileName.$1.log"
}
echo -n"Enter fileName:"
read fileName
name1=$(makeName"type1")
name2=$(makeName"type2")
echo $name1
echo $name2
[更新]
更新后的问题表明,您打算读取makeName函数内部的另一个值,而该函数还打算向用户提示echo。因此,在这种情况下,命令替换方法将不起作用-您需要使用全局变量,例如
makeName() {
echo -n"Enter Ext:"
read ext
__="$fileName.$1.$ext.log"
}
echo -n"Enter fileName:"
read fileName
makeName"type1" ; name1=${__}
makeName"type2" ; name2=${__}
echo $name1
echo $name2
$ ./sample.sh
Enter fileName:filename
Enter Ext: ext1
Enter Ext: ext2
filename.type1.ext1.log
filename.type2.ext2.log
更好的做法是,为了使代码更简洁并避免在函数内部使用全局变量,可以使用"从Bash函数返回值"中所述的方法,并将返回变量的名称作为参数传递,并且理想情况下还将fileName作为参数传递:
makeName() {
local __type=$1
local __fileName=$2
local __resultvar=$3
local ext
local myresult
echo -n"Enter Ext:"
read ext
myresult="$__fileName.$__type.$ext.log"
eval $__resultvar="'$myresult'"
}
echo -n"Enter fileName:"
read fileName
makeName"type1" $fileName theResult ; name1=${theResult}
makeName"type2" $fileName theResult ; name2=${theResult}
echo $myresult
echo $name1
echo $name2
旁注:请参阅为什么在Bash中应避免使用eval,而应该使用什么呢?讨论为什么应避免使用eval。当使用bash 3.1或更高版本时,可以使用printf代替eval:
...
printf -v"$__resultvar" '%s'"$myresult"
...
最后,在bash 4.3或更高版本中,我们可以使用declare -n将nameref属性分配给变量,以便该变量实际上是对另一个变量的引用:
...
declare -n myresult=$3
myresult="$__fileName.$__type.$ext.log"
...
嗨,安德里亚斯,我已经更新了我的问题。
请参阅我更新的答案-本质上,您滥用了return,并且当您的函数打算将输出打印到stdout时(返回值除外),还需要使用@konsolebox建议的方法。
谢谢安德烈亚斯。现在工作正常。 :)
theResult仍然是全局变量;您只是采用了更复杂的路径(使用eval更危险)来设置它。
@chepner是的,但仅在全局范围内使用,而不在函数内使用。因此,函数封装得很好-适当的封装通常会更复杂;)无论如何,我认为每种方法都有其优缺点,您仍然需要明智地决定在特定情况下使用哪种方法...
通常,封装意味着不会全局访问局部变量,而不是仅全局使用局部变量。
好的,因为我的想法已经包含在这里,下面再给我一个提示:由于返回的值是一个普通值而不是数组,因此可以不使用eval,而只需使用printf:printf -v"$__resultvar" %s"$myresult"。您需要Bash 3.1。
同样,从Bash 4.3开始,我们已经可以使用最优雅的解决方案declare -n。
@konsolebox printf完美运行!
更好的方法是选择一个您始终可以使用的常规变量。例:
makeName() {
__="$fileName.$1.log"
}
echo -n"Enter fileName:"
read fileName
makeName"type1"
name1=$__
makeName"type2"
name2=$__
echo"$name1"
echo"$name2"
仅仅为了从函数中获取值而召唤子shell确实是低效而缓慢的。
子外壳+1的好处-Id仍然比全局变量更喜欢子外壳;-),但是您的方法肯定更快(将两个makeName调用循环1000次所需的时间不到100ms,而基于子外壳的解决方案则需要花费100ms差不多2秒)。
bash的神秘本质永远不会令我惊叹:-)
只需将return替换为echo:
makeName()
{
echo"Enter Ext:">&2
read ext
echo"$fileName.$1.$ext.log"
}
最后将Enter Ext:作为结果的一部分...
哎呀。应该使用echo"Enter Ext:">&2或使用bash实现的read可用的-p选项来将提示打印为标准错误,而不是显示提示(read -p"Enter Ext:" ext)。
...,而且,在调用makeName时,您仍然需要使用命令替换(OP不能正确执行,并且导致我们刚才使用@konsolebox;-进行讨论))