Как вычислить значения в сценарии оболочки?

Можно перечислить содержание архива и затем передать список комнате с помощью xargs

Пример для tarball (тестируют его без rm сначала):

tar tfz archive.tar.gz | xargs rm -rf
3
06.11.2011, 18:18
3 ответа

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

Ваш код является субоптимальным. $(wc -l) будет считать количество соответствий возвращенным grep, но существует более простой путь: выполненный grep -c вместо этого. $(ls | wc -l) ненадежный способ считать неточечные файлы в текущем каталоге, потому что вывод ls не надежно; $(set -- *; echo $#) надежный способ сделать это (предполагающий, что существует по крайней мере один файл соответствия; если то предположение не могло бы содержать, использовать $(set -- *; if [ -e "$1" ]; then echo $#; else echo 0; fi, но обратите внимание, что это приведет к делению на нуль, ниже которого необходимо рассматривать как состояние ошибки так или иначе). Таким образом, можно написать код этот путь:

matches=$(grep -c "bla bla blah" blah*)
files=$(set -- *; echo $#)
echo "Blah: $matches / $files * 100"

или можно встроить вычисление этих двух промежуточных значений:

echo "Blah: $(grep -c "bla bla blah" blah*) / $(set -- *; echo $#) * 100"

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

echo "Blah: $(($matches * 100 / $files))"

В ksh93, zsh и yash, но не в других оболочках, Вы получаете арифметику с плавающей точкой, если существует что-то в выражении для принуждения с плавающей точкой, такие как константа с плавающей точкой. Эта функция не присутствует в Оболочке Bourne, ksh88, pdksh, удар, пепел.

echo "Blah: $(($matches * 100.0 / $files))"

bc утилита выполняет операции на десятичном числе с произвольной точностью.

echo "Blah: $(echo "scale=2; $matches * 100 / $files" | bc)"

Другая стандартная утилита, которая может выполнить вычисление с плавающей точкой (с меньшим количеством доступных математических функций) awk.

echo "$matches" "$files" | awk '{print "Blah:", $1 * 100 / $2}'
4
27.01.2020, 21:15
  • 1
    Можно также установить nullglob опция оболочки не избежать "никаких файлов соответствия возвращает проблему" шаблона шарика. num_files=$(shopt -s nullglob; set -- *; echo $#) –  janmoesen 06.11.2011, 22:22

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

Также очень важно, чтобы Вы не анализировали вывод ls. Существует хорошая документация относительно того, почему не сделать, таким образом, здесь.

Кроме того, из чего Вы пытаетесь получить вывод процента? Вы, кажется, не пытаетесь вычислить процент в конце. На данный момент я просто сделал точное вычисление, которое Вы перечислили.

Вот маленький сценарий, который должен смочь сделать, это без проблем упомянуло:

#!/bin/bash

_die() {
    printf '%s\n' "${@:2}"
    exit "$1"
}

(( $# )) || _die 1 "Usage: ${0##*/} pattern <dir>"

[[ $2 ]] && _dir=$2 || _dir=.

[[ -d ${_dir} ]] || _die 2 "Directory does not exist: ${_dir}"

for _file in "${_dir}"/*; do
    [[ -f ${_file} ]] && _files+=( "${_file}" )
done

(( ${#_files[@]} )) || _die 3 'No files matched by glob, not attempting to divide by 0.'

# We pass the same files found to grep instead of reglobbing to avoid a race condition.
while IFS= read -r _number_of_matches; do
    (( _total_matches )) && (( _total_matches+=_number_of_matches )) || _total_matches=${_number_of_matches}
done < <(grep -hc "$1" "${_files[@]}")

(( _total_matches )) || _die 4 "Nothing matched by expression: $1"

printf 'Blah: %s\n' "$(bc <<< "${_total_matches}/${#_files[@]}")"

Примите во внимание это bc не является портативным. Если Вы не возражаете использовать целочисленную арифметику, Вы могли бы использовать оболочку, чтобы вычислить и возвратить ее вместо того, чтобы передать ее bc при помощи $((.

2
27.01.2020, 21:15
  • 1
    Если бы существует способ получить результат без использования сценариев, я был бы благодарен! И да, я использую удар. –  jokerdino 06.11.2011, 15:05
  • 2
    @jokerdino, Помещенный это в функцию в Вашем ~/.bashrc затем (примечание, Вы также захотите получить ~/.bashrc от ~/.bash_profile. –  Chris Down 06.11.2011, 16:21
  • 3
    Если Вы принимаете удар так или иначе, shopt -s nullglob намного более легкий способ обработать случай когда * не соответствует. Кроме того, до н.э является стандартным. –  Gilles 'SO- stop being evil' 06.11.2011, 18:15
  • 4
    @Gilles Много Нельдов не включает bc по умолчанию (Дуга Linux бесцеремонно). Что касается nullglob, я должен был бы все еще сделать проверки независимо. –  Chris Down 06.11.2011, 18:28

Что-то вроде этого?

echo "scale=2;100*`grep 'bla bla bla' bla* | wc -l`/`cat bla* | wc -l`" | bc
0
27.01.2020, 21:15
  • 1
    Эта команда опасна (состояние состязания). –  Chris Down 06.11.2011, 14:38
  • 2
    Эта команда действительно предоставляет мне желаемый вывод. Это действительно опасно? Есть ли какие-либо более безопасные альтернативы? –  jokerdino 06.11.2011, 15:34
  • 3
    Ну, столь же "опасный" как команда, делающая, это может быть, то есть, Вы рискуете получить полный неправильный результат. –  Chris Down 06.11.2011, 16:20
  • 4
    @jokerdino, Если файл bla* создан или удален, в то время как Вы выполняете эту команду, затем grep и cat может работать через различные наборы файлов. Я не знаю где cat bla* прибывает из, тем не менее, это, кажется, не находится в требованиях. –  Gilles 'SO- stop being evil' 06.11.2011, 18:18
  • 5
    Где состояние состязания? Код в обратных галочках должен быть оценен, прежде чем целый аргумент передается "эху"? Существует две части кода с обратными галочками, и порядок, в котором они выполняются, не имеет значения. –  rvdginste 07.11.2011, 11:16

Теги

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