Bash, если условия переменных в интервалах

В openSUSE есть несколько способов перечислить установленные файлы. С Zypper, я would try:

zypper search -i

Or:

zypper search --installed-only

С RPM можно попробовать:

rpm -ql packageName | less
0
12.07.2014, 22:32
4 ответа
[

][]bash[] вроде бы не поддерживает ни сравнение диапазонов, ни числа с плавающей точкой, поэтому мы должны сделать это сами. Я также собираюсь определить функцию и использовать []bc[] для вычисления чисел с плавающей точкой. Вот конечный результат и набор тестов:[

] [
# Call as `compareRanges start end b1 f1 b2 f2 b3 f3...`
compareRanges() {
    local t_initial=$1
    local t_final=$2
    shift 2
    while [ ${#@} -gt 1 ]
    do
        local in_range=$(bc <<<"$t_initial >= $1 && $t_final <= $2")
        if [ $in_range = 1 ]
        then
            # Debugging output to stderr - can be removed:
            echo "[$t_initial,$t_final] is within [$1,$2]" >&2
            return 0
        fi
        shift 2
    done
    # Debugging output to stderr - can be removed:
    echo "[$t_initial,$t_final] is not within any ranges." >&2
    return 1
}
# Basic integers from the example
compareRanges 1 3 2 4 && echo BAD || echo OK
compareRanges 1 3 1 3 && echo OK || echo BAD
compareRanges 1 3 0 4 && echo OK || echo BAD
# Fractional numbers
compareRanges 1.5 2.5 1.1 2.2 && echo BAD || echo OK
compareRanges 1.5 2.5 0.3 3.1 && echo OK || echo BAD
# Multiple ranges
compareRanges 5 7 1 4 2 6 3 9 && echo OK || echo BAD
compareRanges 5 7 1 2 3 4 5 6 7 8 && echo BAD || echo OK
] [

]Функция []comparisonRanges[] принимает как минимум два аргумента. Первый - ваш []t_initial[], а второй - ваш []t_final[]. После этого может произвольно потребоваться много других аргументов в парах, а именно: []begin1[], []fin1[], []begin2[], []fin2[], по порядку.[

] [

] В первом тестовом примере сравниваются диапазоны в комментариях к этому вопросу: 1-3 и 2-4. [

] [
compareRanges 1 3 2 4 && echo BAD || echo OK
] [

] Итак, [] 1 [] это [] t_initial [], [] 3 [] это [] t_final [], [] 2 [] это [] begin1 [], и [] 4 [] это [] fin1 []. [

] [

] Когда вы хотите использовать несколько диапазонов, вы перечисляете их все парами позже: [

] [
compareRanges 5 7 1 4 2 6 3 9 && echo OK || echo BAD
] [

] Здесь мы тестируем с 1-4, 2-6, и 3-9. В цикле [] в то время как [] мы по очереди смотрим на каждую пару и сравниваем ее с []t_initial[] и []t_final[].[

] [

] Потому что []bash[] не поддерживает дробные числа, мы используем [][]bc[][], калькулятор произвольной точности. Его вход дается частью []<<<"$t_initial >= $1" ...[]: которая подает строку на стандартный вход. []$1[] - начало диапазона, на который мы сейчас смотрим в этой итерации цикла, а []$2[] - конец; мы сравниваем и нижнюю, и верхнюю границу сразу с []&&[]. []bc[] выдаст []1[], когда сравнение будет истинным, и []0[], когда ложным. Мы сохраняем результат в []in_range[], и функция успешно работает ([]return 0[]), когда оба наших теста были истинны.[

] [

]Дробные числа можно просто указывать с их обычной десятичной формой:[

] [
compareRanges 1.5 2.5 0.3 3.1 && echo OK || echo BAD
] [

][]bc[] будет обрабатывать числа с любым количеством дробных цифр и любой необходимой амплитудой.[

] [

]В конце, если ни одна из пограничных пар не совпала, мы не сможем ([]return 1[]). Вы можете использовать функцию как:[

] [
if compareRanges $t_initial $t_final 2 4 11 19
then
    ...
fi
] [

]Тестовый набор должен вывести все "OK" при запуске.[

] [
] [

]В качестве альтернативы, другие оболочки (такие как [][]zsh[][]) []do[] поддерживают значения дробных переменных. Если бы вы могли запустить свой скрипт в одном из них, вы могли бы избежать использования []bc[], хотя сравнение все же лучше в функции. По крайней мере, в случае []zsh[] они являются плавающими, поэтому они не обязательно точны; []bc[] всегда будет правильным.[

].
1
28.01.2020, 02:17

Не уверен, понравится ли вам это решение. У него есть 2 особенности:

  • Внешних программ не требуется
  • Он использует функцию, так что, по крайней мере, в нем скрывается сложность сравнений

Вот оно:

#!/bin/bash

# The comparing function
function compareInterval {
 t1=$1
 t2=$2

 shift 2

 while (( "$2" )); do
   if ((  $t1 >= $1  &&  $t2 <= $2 )); then
     # got match
     return 0
   fi
   shift 2
 done

 return 1
}

# sample values
t_initial=2
t_final=4

# Invocation. Compares against 1-3, 3-5, 2-5
if compareInterval  $t_initial $t_final  1 3  3 5  2 5; then
 echo Got match
fi
3
28.01.2020, 02:17
[

]То, что вы спрашиваете о "11...19", называется brace expansion. [

] [

] Вы можете использовать либо []eval {$t_initial. .$t_final}[] ,[

] [

]...или [

] [

][], если `сек $t_initial...$t_final`==$somevalue[][

]
0
28.01.2020, 02:17
[

] Вот пара бесстыдных грабежей ответа LatinSuD, которые обрабатывают плавающую точку.  Вы заметите, что его ответ может похвастаться "Внешние программы не нужны".  Он использует программу калькулятора, []bc[], как он и предлагал:[

] [
#!/bin/bash

# The comparing function
function compareInterval {
 t1=$1
 t2=$2

 shift 2

 while (( "$2" ))
 do
   # if ((  $t1 >= $1  &&  $t2 <= $2 ))
   bc_result=$(echo "print $t1 >= $1  &&  $t2 <= $2" | bc)
   if [  "$bc_result" = 1 ]
   then
     # got match
     return 0
   fi
   shift 2
 done

 return 1
}

# sample values
t_initial=2.3
t_final=4.2

# Invocation. Compares against 1-3, 3-5, 2-5
if compareInterval  $t_initial $t_final  1 3  3 5  2 5
then
 echo Got match
fi
] [

]Это просто берет тест [] if (( $t1 >= $1 &&$t2 <= $2 ))[] и отправляет его в []bc[], и затем захватывает выход из []bc[].[

] [
] [

]Другой подход заключается в нормализации чисел к целым числам путем умножения на десятку.  Для этого необходимо иметь максимальное количество десятичных цифр.  Например, если ни одна точка данных не имеет более трех цифр справа от десятичной точки, мы можем умножить все на 1000.[

] [
#!/bin/bash

# Normalize function: it multiplies a floating point number by 1000
# without using floating point arithmetic.
normalize()
{
  case "$1" in
    *.*)
        result=$(echo "$1"000 | sed 's/\(.*\)\.\(...\).*/\1\2/')
        ;;
    *)
        result="$1"000
  esac
  echo "$result"
}

# The comparing function
function compareInterval {
 t1=$(normalize $1)
 t2=$(normalize $2)

 shift 2

 while (( "$2" ))
 do
   a1=$(normalize $1)
   a2=$(normalize $2)
   if ((  $t1 >= $a1  &&  $t2 <= $a2 ))
   then
     # got match
     return 0
   fi
   shift 2
 done

 return 1
}

# sample values
t_initial=2.3
t_final=4.2

# Invocation. Compares against 1-3, 3-5, 2-5
if compareInterval  $t_initial $t_final  1 3  3 5  2 5
then
 echo Got match
fi
] [

] Если параметр функции [] нормализовать[] представляет собой простое целое число. (т.е. число без десятичной точки, например, []17[]). мы можем умножить на 1000, просто добавив []000[], так что []17[] → []17000[].  Если параметр к [] нормализовать[], то это число с плавающей точкой (т.е. содержит десятичную точку, например, []42,5[]), мы все еще добавляем []000 [], и затем с помощью []sed[] удалите десятичную точку и все после третьей цифры.  Команда []sed[] []s/\(.*\)\.\(...\).*/\1\2/[] принимает строку типа []abcdef[].[]ghijkl[]. и возвращает [] abcdefghi [], поэтому []42,5[] → []42,5000[] → []42500[] (т.е. 42,5 × 1000).[

] [

] Эту манипуляцию со строками можно выполнить полностью в []bash[], не используя []sed[].[

].
1
28.01.2020, 02:17

Теги

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