在bash中的函数中设置位置参数
Posted
技术标签:
【中文标题】在bash中的函数中设置位置参数【英文标题】:setting a positional parameter in a function in bash 【发布时间】:2017-05-04 02:18:45 【问题描述】:我正在制作一个函数,可以根据需要轻松地将我的字符串转换为数组。
我有点遇到一个奇怪的问题。我还是 bash 的新手,这真的让我很烦。有人能对此有所了解吗?
convert.sh
#!/bin/bash
convert2array ()
read -a $1_arr <<< $1
mx=$(dig +short google.com mx | cut -d' ' -f 2 | sed 's/\.$//')
convert2array "$mx"
echo $mx_arr[@]
输出:
bash -x convert2array.sh
++ sed 's/\.$//'
++ cut '-d ' -f 2
++ dig +short google.com mx
+ mx='alt2.aspmx.l.google.com
alt3.aspmx.l.google.com
alt1.aspmx.l.google.com
aspmx.l.google.com
alt4.aspmx.l.google.com'
+ convert2array mx
+ read -a mx_arr
+ echo 585911
585911
【问题讨论】:
【参考方案1】:如果数组只是一次性的,对于只读输出循环,POSIX shell可以做到:
set -- `dig +short google.com mx` ; \
while [ "$2" ] ; do echo "$2%.*" ; shift 2 ; done
输出:
alt2.aspmx.l.google.com
alt3.aspmx.l.google.com
alt4.aspmx.l.google.com
alt1.aspmx.l.google.com
aspmx.l.google.com
如果输出需要进一步处理,请将echo
传递给它需要做的任何其他事情。
注意:上面的代码包含一个简单的 kludge 来避免 sed
和 cut
-- 而是只输出 偶数 数组成员,并使用 parameter expansion "删除Smallest Suffix Pattern" 删除那个 '.'最后。
【讨论】:
【参考方案2】:您可以直接将dig
结果存储在数组中
declare -a results=( $( dig +short google.com mx | cut -d' ' -f 2 | sed 's/\.$//' ) )
echo "$results[@]"
另外,你不需要在这里使用cut
,单独使用sed
就足够了。
declare -a results=( $( dig +short google.com mx | sed -E 's/^[[:digit:]]*[[:blank:]]*(.*)\.$/\1/') )
echo "$results[@]"
aspmx.l.google.com
alt1.aspmx.l.google.com
alt2.aspmx.l.google.com
alt4.aspmx.l.google.com
alt3.aspmx.l.google.com
请参阅[ bash arrays ]、[ command subsctitution ] 和 [ positional parameters ]。
警告您:输出只能是一种格式。尽管( $( .. ) )
是comment#1 中指出的反模式,但对于这种情况,它就足够了。
【讨论】:
通过双引号替换命令,您总是会创建一个包含 所有行 的 single 元素的数组,这不是本意。如果没有双引号,输出行总是会受到分词和通配符的影响,即使这恰好在 this 情况下起作用,( $(...) )
也不是将命令输出读入的一般稳健方式一个数组(除非您设置 $IFS
并关闭通配符,这不值得)。
@mklement0 :感谢您的指点。我想了想,但后来忘了把双引号去掉,急着发表答案:) 现在改了
@mklement0 : 另外,我同意你评论的第二部分
我很高兴听到这个消息,但我真的希望您在解决方案前加上一个明显的警告。我认为( $(...) )
是一种不应该推广的反模式。它非常简单,但它会回来咬你——见mywiki.wooledge.org/…
@mklement0 : 说得好,让我想起了Bourne shell 中的阴暗角落,人们都在使用它们——Chet Ramey【参考方案3】:
尝试以下方法:
convert2array ()
# Bash v4+ alternative: `readarray -t` instead of `IFS=$'\n' read -d '' -ra`
IFS=$'\n' read -d '' -ra "$1" <<<"$2"
mx=$(dig +short google.com mx | cut -d' ' -f 2 | sed 's/\.$//')
convert2array mx_arr "$mx"
printf '%s\n' "$mx_arr[@]"
至于你尝试了什么:
convert2array
中的$1
不是输入变量$mx
的名称,而是它的值。
您需要将要显式声明的变量的名称(可能在修改输入名称之后)作为单独的参数传入。
read
默认情况下只读取输入的 第一 行,而您传递 多个 行。-d ''
使 @ 987654327@ 读取所有行,IFS=$'\n'
使read
读取每一行。
在 Bash v4+ 中,使用内置的readarray
,IFS=$'\n' read -d '' -ra
可以替换为readarray -t
。
命令的简化版本是使用 Bash v4+ readarray
内置函数将 dig ...
输出行直接读取到数组中:
readarray -t mx_arr < <(dig +short google.com mx | cut -d' ' -f 2 | sed 's/\.$//')
Bash v3.x 替代方案:
IFS=$'\n' read -d '' -ra mx_arr < <(dig +short google.com mx | cut -d' ' -f 2 | sed 's/\.$//')
【讨论】:
【参考方案4】:只是说明你的函数出了什么问题:
convert2array ()
read -a $1_arr <<< $1
在这里,当您想要读取变量本身的内容时,您正在读取$1
的内容,这是变量的名称。你可以在这里使用间接:
convert2array ()
read -a $1_arr <<< $!1
正如其他人所指出的,有更简单的方法可以将您的输出保存在数组中。
【讨论】:
以上是关于在bash中的函数中设置位置参数的主要内容,如果未能解决你的问题,请参考以下文章