2014-09-26 58 views
1

我正在整理一些bash的代码。我有一堆行,像下面的例子那样设置变量,除非已经设置了,使用给脚本的命令行参数。bash函数可以访问和操作脚本的命令行参数吗?

[[ -z "${myvar1}" && -n $1 ]] && myvar1="$1" && shift 
[[ -z "${myvar2}" && -n $1 ]] && myvar2="$1" && shift 
...repeated many times... 

我想我会写一个函数来做到这一点,这样称呼它

positional_arg myvar1 
positional_arg myvar2 

然而,这需要的功能来访问和操作的参数列表。我不知道这是可能的,所以这是我想出了...

args=("[email protected]") 
positional_arg() { 
    local value=$args 
    [[ -z "${!1}" && -n "$value" ]] && eval "$1='$value'" && args=(${args[@]:1}) 
} 

,我知道这样做的问题是,

  • 这取决于全球args阵列使用前设置
  • 构造args=(${args[@]:1})其中转变该数组不适用于空白,所以这将不适用于包含空白的参数。

所以,我想发现一个函数是否可以访问和操作其脚本的位置参数。

另外,在bash中实现这种功能的任何替代建议都会受到欢迎,特别是如果它们克服了上述问题!

(GNU bash, version 4.3.18(1)-release) 

回答

2

首先,你可能要考虑使用简单

: ${myvar1:=$1} 
: ${myvar2:=$2} 
# etc 

这只是设置myvar1$1值(空或不)仅如果myvar1已经没有非空值。


local args=(${args[@]:1})不保留空白,但local args=("${args[@]:1}")一样。

由于[email protected]同时用于shell和函数的位置参数,所以在调用函数之前,您将不得不将shell参数复制到已知的全局变量中。当然,如果你真的想修改的参数,你还必须在函数返回后(如args=("[email protected]"); my_function; set -- "${args[@]}")复制它们。

另一种方法是通过外壳参数作为附加功能参数:

my-function() { 
    local_args=() 
    while [[ $1 != "--" ]]; do 
     local_args+=("$1") 
     shift 
    done 
    shift 
    # [email protected] is now a copy of the shell arguments, 
    # but you'll still have to copy them to a global 
    # if you want to make any changes visible post-call 
} 
my-function arg1 args2 -- "[email protected]" 
+0

感谢您的空白修复!你可以在你的例子中解释'set - “$ {args [@]}”'“吗? – starfry 2014-09-26 14:44:57

+0

@starfry,它从'args'数组中设置参数列表('$ 1','$ 2'等)。 – 2014-09-26 14:59:59

+0

@chepner:我最初有'$ {myvar1:= $ 1} ...'但改变了它,因为位置参数分配是在用'getopts'解析选项来填充仍然未分配的变量之后出现的。因此,变量到参数的映射根据选项的使用情况而变化。但是,是的,在一致的情况下,我正是这样做的。 – starfry 2014-09-27 10:36:58

2

您也可以在一个循环中间接设置的变量(不potentionally危险EVAL):

#!/bin/bash 

#set variables in order from "[email protected]" 
for var in myvar1 myvar2 v3 x   #names of the variables... 
do 
    #use one of the following to assgin to the variable 
    printf -v "$var" "%s" "$1" && shift #print into variable 
    #read -r "$var" <<< "$1" && shift #read into variable 
    #declare "$var"="$1" && shift  #declare a variable 
done 

#print the content of the variables 
echo "=$myvar1=$myvar2=$v3=$x=" 

#or indirectly: 
for var in myvar1 myvar2 v3 x 
do 
    echo "$var:>>${!var}<<" 
done 
echo "Unused/remaining args:" 
printf ">>%s<<\n" "[email protected]" 

什么调用如:

script '1 1' 2 3 '4 4' 5 6 

打印

=1 1=2=3=4 4= 
myvar1:>>1 1<< 
myvar2:>>2<< 
v3:>>3<< 
x:>>4 4<< 
Unused/remaining args: 
>>5<< 
>>6<< 

总之,使用非常重要的位置因变量是未来难以调试的源泉......恕我直言,在情况下,当脚本必须采取很多不同的变量,是更好地使用getopt并使用脚本

script -i vali -o valo .... -z valz # ;) 
+0

避免邪恶'eval'总是好事!那里有用的提示;我必须至少承诺其中之一才能回忆。另外,在处理位置参数之前,我正在使用'getopts'。两种方式都有其优点。我只是在@ chepner的回答评论中描述了我正在做的事情。谢谢你的建议,谢谢。 – starfry 2014-09-27 10:48:32

0

最简单的方法是调用positional_arg[email protected]

positional_arg [email protected] 

通过它的命令行变量然后,你将获得牛逼他在函数内部使用命令行参数,使用$1,$2等。

$0将是脚本的名称。

如果您需要发送更多变量,您可以简单地将它们添加到命令行参数之后。

positional_arg [email protected] $test 

这只会增加数组的大小。

,如果这是你的一个问题,简单的前[email protected]

positional_arg $test [email protected] 

添加其他变量,在这种情况下,你知道你有多少变量发送的功能,因此,你可以在做津贴的你的函数中的变量调用。

$0在这种情况下,仍然是脚本的名称,所有其他引用都会增加您添加的变量的数量。

在上面的例子中$1函数调用之前,变成$2函数内。

+0

想法是'positions_arg'函数从全局列表中吃掉了arg。 – starfry 2017-07-16 12:51:33