сценарий удара с простой включенной математикой

Я являюсь новым со сценариями, и я хочу записать сценарий, который должен обработать, это - аргумент (аргументы) как следующее:

$ tandenstokers "| | x|| | |+|"
|| x |||| + | = 9 (11 tandenstokers)

$ tandenstokers \| \| x\|\| \| \|\+\|
|| x |||| + | = 9 (11 tandenstokers)

Где, поскольку я получаю это, как произведено:

$ tandenstokers \| \| x\|\| \| \|\+\|
|| x |||| + | = 0 (0 tandenstokers)

То, что это делает, в основном считать сумму 'палок' и применить простую математику к нему. Получающийся вывод: 1. Данный аргумент (аргументы) с только располагает с интервалами оставленный прежде и после x или + 2. 9 в примере выше результат математики. 3. 11 сумма палок, используемых в формуле (+ и количество x как две палки)

До сих пор у меня есть следующий код, и я не понимаю, где моя ошибка:

#!/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)"
2
задан 7 December 2016 в 20:32

3 ответа

В первую очередь, для ответа на вопрос, -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'
  • думайте оболочка (я знаю, что это трудно, когда Вы изучаете sh): разделите свой код на маленькие команды (функции), используйте параметры и используйте в своих интересах синтаксический анализатор оболочки (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 формулу в регулярной арифметической формуле, с которой я наконец оцениваю $(( ... )).

Я оставляю Вас как осуществление количество зубочисток в формуле.

1
ответ дан 2 December 2019 в 01:56

Это - мое рабочее решение для проблемы:

#!/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)"
0
ответ дан 2 December 2019 в 01:56

Я боюсь, что Ваш сценарий не очень легко понять. Ваш подход кажется чрезмерно сложным для того, что он пытается сделать и так как Вы не объясняете, что Вы думаете, что каждая часть Вашего сценария делает, это не тривиально для понимания этого.

Тем не менее Ваш первый выпуск (то, которое было бы очевидно, имело Вас, включал сообщения об ошибках), то, что Вы используете -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 символы долго.

Первое правило к программированию на любом языке: когда что-то пойдет не так, как надо, распечатайте все переменные. 9 раз из 10, проблема состоит в том, что переменная не имеет значения, Вы думаете, что это имеет.

В любом случае у Вас есть слишком много проблем для отладки здесь, и было бы намного более просто потребовать с нуля. Например, этот сценарий делает то, что Вы хотите:

#!/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)
4
ответ дан 2 December 2019 в 01:56

Другие вопросы по тегам:

Похожие вопросы: