2016-11-24 47 views
2

我想将我的shell脚本转换为使用datadriven方法。但是由于在任何shell中都没有“表格”类型的值(我知道),有什么建议替代方法来做到这一点?Datadriven shell编程?建议,请

我正在寻找的是解决方案,将允许人们做这样的事情:

animals = [['horse', 300 'brown'], 
      ['cat', 3, 'black'], 
      ['elephant', 3000, 'grey'], 
      ['mouse', 0.3, 'grey']] 
for a in animals ; do 
    echo "A typical $a[1] is $a[3] and weighs about $a[2] kilograms." 
done 

更确切地说,我想尝试一些命令,看看其中的一个是可用的,然后发送参数:

commands = [['c1', '-m', '-i'], 
      ['c2', '-message', '-icon'], 
      ['c3', '/m', '/i']] 
for c in commands ; do 
    if exists c[1] ; then 
    command = c[1] 
    message_option = c[2] 
    icon_option = c[3] 
    break; 
    fi 
done 
$command $message_option "message" $icon_option icon 
+0

为什么不把你的'表'数据放到一个文件中,然后用'awk'或类似的程序读取它呢? – VM17

+0

你正在使用哪个外壳? 'bash','ksh'或'zsh'? – Inian

+0

我正在考虑'python',但是因为可移植性问题而决定不使用它。所以我的做法是'bash'。该脚本需要做很多其他的事情,但是探索与'awk'结合会很有趣,因为它也可以“随处可见”。那么一个shell脚本如何调用'awk'来做这个例子(我将更新它以更精确地指出我需要做什么)? – thoni56

回答

4

没有bashisms需要。

#!/bin/sh 
while read animal weigth colour; do 
    printf '%s\n' "A typical $animal is $colour and weighs about $weight kilos." 
done << EOF 
horse 300 brown 
cat 3 black 
elephant 3000 grey 
mouse 0.3 grey 
EOF 

观察如何按名称引用的元素与1,不神秘的索引,2,3,它不叉:这可以用这里文档while read循环中读取被干净利落地解决了/ exec任何外部命令并击败另一个答案中看到的循环体中的3个awk。

+2

@Inian和Jens是非常令人迷惑笑 – 2016-11-24 10:46:20

+2

@Mayerz而且我们不是唯一的:-) – Jens

+0

@Jens:提供了使用只是因为OP的帖子看起来类似阵列的方法。 – Inian

0

试试这个吗?

cat file 
'horse', 300, 'brown' 
'cat', 3, 'black' 
'elephant', 3000, 'grey' 
'mouse', 0.3, 'grey' 

for i in {1..4} ; 
do 
    animal=$(awk -F, -v var="$i" 'NR== var {print $1}' file) 
    weight=$(awk -F, -v var="$i" 'NR== var {print $2}' file) 
    colour=$(awk -F, -v var="$i" 'NR== var {print $3}' file) 
    echo "A typical "$animal" is "$colour" and weighs about "$weight" kilos." 
done 

输出 -

A typical 'horse' is 'brown' and weighs about 300 kilos. 
A typical 'cat' is 'black' and weighs about 3 kilos. 
A typical 'elephant' is 'grey' and weighs about 3000 kilos. 
A typical 'mouse' is 'grey' and weighs about 0.3 kilos. 
+0

这是CPU周期的浪费。它分叉12个进程并读取同一文件12次。 – Jens

+0

表现不是要求之一,但在某些情况下这可能是有效的观察。 – thoni56

2

您可以定义和bash使用associative-arrays您的需求。

#!/bin/bash 

# declaring the Associative array 
declare -a animals 

animals[0]="'horse':300:'brown'" 
animals[1]="'cat':3:'black'" 
animals[2]="'elephant':3000:'grey'" 
animals[3]="'mouse':0.3:'grey'" 

for animal in "${animals[@]}" 
do 
    myArray=(${animal//:/ }) 
    printf "A typical "${myArray[0]}" is "${myArray[2]}" and weighs about "${myArray[1]}" kilograms.\n" 
done 

在上述唯一棘手的部分是类型的parameter-expansion

${parameter/pattern/string} 
      The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. 
If pattern begins with ‘/’, all matches of pattern are replaced with string. Normally only the first match is replaced. 

所以理想的是串'horse':300:'brown'被分割为各个元件和存储其随后用于访问各个元件阵列myArray在一个C风格的循环。

+0

很明显,我不知道阵列中的'bash' ... Duh ... – thoni56

+0

@ thoni56:我以为你需要一个使用你的例子中的数组的方法!但现在未被接受? :( – Inian

+1

我并没有特别要求如何实现数组,而是数据驱动的shell脚本。我接受了你的答案,因为它当时绝对是最好的答案,而且我仍然投票赞成你给我讲解bash数组,但@Jens的回答对我的实际问题来说是一个更好的解决方案。考虑接受他的回答是一个信号,他对我想达到的目标的理解甚至比你的更好。 – thoni56