我是脚本新手,我想编写一个脚本来处理它的参数,如下所示:
$ tandenstokers "| | x|| | |+|"
|| x |||| + | = 9 (11 tandenstokers)
$ tandenstokers \| \| x\|\| \| \|\+\|
|| x |||| + | = 9 (11 tandenstokers)
当我得到这个输出时:
$ tandenstokers \| \| x\|\| \| \|\+\|
|| x |||| + | = 0 (0 tandenstokers)
它的作用基本上是计算“棍子”的数量并对其进行简单的数学运算。结果输出为:1. 给定的参数,在 x 或 + 之前和之后只留有空格 2. 上例中的 9 是数学运算的结果。3. 11 是公式中使用的棍子数量(a + 和 ax 算作两根棍子)
到目前为止,我有以下代码,但我不明白我的错误在哪里:
#!/bin/bash
uitdrukking="$*"
size=${#uitdrukking}
mooi=$(echo "$uitdrukking" | sed -e 's/ //g' | sed -e 's/+/ + /g' | sed -e 's/x/ x /g')
x=0
y=1
a=1
n=0
m=0
sub=0
while [ $a -le $size ]
do
((a++))
if [ ${uitdrukking:$x:$y} -eq "|" ]
then
((n++))
((x++))
((y++))
((m++))
elif [ ${uitdrukking:$x:$y} -eq "+" ]
then
((x++))
((y++))
m=$[ $m + 2 ]
elif [ ${uitdrukking:$x:$y} -eq "x" ]
then
((x++))
((y++))
m=$[ $m + 2 ]
while [ ${uitdrukking:$x:$y} -eq "|" ]
do
((sub++))
((x++))
((y++))
((m++))
done
n=$[ $n * $sub ]
else
((x++))
((y++))
fi
done
echo "$mooi = $n ($m tandenstokers)"
通过从头开始采用不同的方法解决了这个问题,得到了以下正确的代码:
#!/bin/bash
echo "$(echo "$*" | sed -e 's/ //g' | sed -e 's/+/ + /g' | sed -e 's/x/ x /g') = $(($(echo "$*" | sed -e 's/ //g' | sed -e 's/\(\|[^x+]*\)/(\1)/g' | sed -e 's/|/1 + /g' | sed -e 's/ + $//g' | sed -e 's/ + +/ + /g' | sed -e 's/ + x/ \* /g' | sed -e 's/ + \([^1]\)/\1/g' | sed -e 's/x/ \* /g'))) ($(($(echo "$*" | sed -e 's/ //g' | sed -e 's/|/1 p /g' | sed -e 's/ p $//g' | sed -e 's/x/2 p /g' | sed -e 's/+/2 p /g' | sed -e 's/p/+/g'))) tandenstokers)"
答案1
恐怕你的脚本不太容易理解。你的方法似乎过于复杂,无法理解它所要做的事情,而且由于你没有解释你认为脚本的每个部分的作用,因此理解起来并不容易。
也就是说,您的第一个问题(如果您包含错误消息,这个问题会很明显)是您使用了-eq
进行词汇比较。您需要的是 ,=
因为您匹配的是字符串,而不是数字。
下一个问题,从错误消息中再次显而易见的是
/home/terdon/scripts/foo.sh: line 15: [: too many arguments
/home/terdon/scripts/foo.sh: line 21: [: too many arguments
/home/terdon/scripts/foo.sh: line 26: [: too many arguments
这是因为各种${uitdrukking:$x:$y}
扩展为包含空格的字符串,而不是单个字符。这可能是因为您在许多地方增加了各种计数器变量,因此您的速度$y
会>1
非常快。我认为(但是,同样,我不能确定,因为您的问题实际上并没有解释您认为发生了什么)您误解了语法的工作原理。它不会从位置到位置${var:x:y}
提取子字符串。它提取从位置开始的子字符串和var
x
y
var
x
y
长字符。
编程的第一条规则任何语言是:当出现问题时,打印出所有变量. 十有八九,问题在于变量没有您认为它具有的值。
无论如何,这里有太多问题需要调试,从头开始会简单得多。例如,此脚本执行您想要的操作:
#!/bin/bash
mooi=$(echo "$*" | sed -e 's/ //g' | sed -e 's/+/ + /g' | sed -e 's/x/ x /g')
## I use fold to print one character at a time and then iterate
## over the resulting strings.
while read char; do
case $char in
## If this is a |, increment the total number of |
## found and the current number (until the next operator).
"|")
((pipeNum++))
((totPipes++))
;;
## If this is an operator
[+x])
## Change x to * for bc
char=$(echo "$char" | tr 'x' '*')
## Increment the operator count by 2 as requested.
operators=$((operators + 2))
## Append the number of pipes so far and the
## current operator to the $string variable. This
## will hold the expression we'll give to bc.
string="$string $pipeNum $char"
## reset the pipeNum to 0 for the next operation.
pipeNum=0
;;
## Ignore all other cases.
"*")
continue
;;
esac
done < <(fold -w 1 <<<"$*")
## Add the last set.
string="$string $pipeNum"
## Count the total
tandenstokers=$((totPipes + operators))
## Use bc to calculate
echo "$mooi = $(echo "$string" | bc) ($tandenstokers tandenstokers)"
要查看实际效果,请执行以下操作:
$ foo.sh '| | x | | | | + |'
|| x |||| + | = 9 (11 tandenstokers)
$ foo.sh \| \| x\|\| \| \|\+\|
|| x |||| + | = 9 (11 tandenstokers)
答案2
首先,回答你的问题,-eq
是用于整数比较。用于=
字符串。我认为这是你的主要错误。
一些忠告:
- 默认引用变量(即
"$n"
不仅仅是$n
)。在某些情况下可能需要取消引用它们,但这必须是例外 - 总是用来
set -u
检测未初始化变量的使用 - 将 sed 指令串联在一个 sed 命令中:
sed -e 's/ //g; s/[+x]/ & /g;'
而不是三条命令管道sed -e 's/ //g' | sed -e 's/+/ + /g' | sed -e 's/x/ x /g'
- 想想 shell(我知道当你学习 sh 时这很难):将代码分成小命令(函数),使用参数并利用 shell 解析器(
for word in "$@"
)。在这里,我看到的是一个包含很多内容的大循环N++
,你自己逐个字符地解析所有内容。
为了代码高尔夫的乐趣,这里是一个 sed + 算术评估中的计算部分:
tandenstokers()
{
echo "$((
$(sed -e '
s/ //g
s/[xX]/*/g
s/|\+/\(&\)/g
s/|/+1/g
' <<< "$*" )
))"
}
$ tandenstokers "| | x|| | |+|"
9
$ tandenstokers "|| + ||| - | X |||| / ||"
3
这是一个完全不同的解决方案。把它当作一种好奇心,不要放弃你的好奇心!我所做的只是将您的 tandenstokers 公式转换为常规算术公式,最后用 进行评估$(( ... ))
。
我留给你一个练习,计算一下公式中牙签的数量。
答案3
这是我针对该问题的解决方案:
#!/bin/bash
echo "$(echo "$*" | sed -e 's/ //g' | sed -e 's/+/ + /g' | sed -e 's/x/ x /g') = $(($(echo "$*" | sed -e 's/ //g' | sed -e 's/\(\|[^x+]*\)/(\1)/g' | sed -e 's/|/1 + /g' | sed -e 's/ + $//g' | sed -e 's/ + +/ + /g' | sed -e 's/ + x/ \* /g' | sed -e 's/ + \([^1]\)/\1/g' | sed -e 's/x/ \* /g'))) ($(($(echo "$*" | sed -e 's/ //g' | sed -e 's/|/1 p /g' | sed -e 's/ p $//g' | sed -e 's/x/2 p /g' | sed -e 's/+/2 p /g' | sed -e 's/p/+/g'))) tandenstokers)"