Отображение спиннера в ожидании завершения какого-либо процесса

Это не тот ответ, который вы ищете, но это практическая альтернатива.


Во-первых, немного предыстории:

У всех типов каналов есть обратная сторона, которую читатель не может искать в них, включая те, которые Bash использует для . Я не знаю, нужно ли GhostScript искать во входных файлах или он просто читает все файлы в памяти, но в целом для многих форматов файлов ввод на основе канала может быть медленнее или использовать больше памяти (из-за отсутствия поиска обходные пути), чем входные файлы.

(Я не уверен, потому что я склоняюсь к надежности. Я хочу, чтобы мои скрипты сначала работали (давали надежные результаты), а затем были легкими и быстрыми. По причинам, перечисленным ниже, избегание временных файлов не дает мне ускорения или меньшее использование ресурсов в системах, которые я использую.)

Во многих (большинстве?) дистрибутивов Linux Solaris (начиная с SunOS 4 и Solaris 2.1), NetBSD (4.0 и новее), FreeBSD (7.0 и новее), DragonFly BSD и OpenBSD (5.5 и новее), / tmp обычно представляет собой tmpfs , RAM- файловая система на основе. В этих системах отказ от временных файлов является контрпродуктивным (за исключением случаев, когда вы точно знаете, что приложения, которым вы его скармливаете, могут обрабатывать ввод как поток, то есть через канал, без недостатков).

Типичные контрпримеры (то есть случаи, когда вы используете канал вместо временных файлов) - это простая фильтрация или обработка, например, sed или awk . GhostScript определенно не является «простой программой фильтрации или обработки».

Все современные операционные системы достаточно умны, чтобы хранить недавно использованные файлы в памяти, а не записывать и читать их из хранилища. (Обычно они сохраняют содержимое на диск один раз, но не читают обратно, в подобных ситуациях с временными файлами.) Таким образом, даже когда / tmp не основано на RAM файловая система, временные файлы хранятся в памяти и не более одного раза записываются на диск. Это означает, что даже в / tmp без ОЗУ временные файлы являются хорошим вариантом.

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

Действительно, обычно причиной нежелания использовать временные файлы является некий вариант

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

С помощью утилиты Bash и mktemp этого легко избежать. Вот уже несколько лет я использую следующую идиому:

#!/bin/bash
Work=$(mktemp -d) || exit 1
trap "cd / ; rm -rf '$Work'" EXIT

Это создает временный каталог (в / tmp / ), который будет автоматически удален при выходе из скрипта. (Linux coreutils mktemp делает каталог доступным только для пользователя-владельца; нет доступа к группе или другим лицам, так что это тоже довольно безопасно.)

Ловушка bash построена -in команда сформулирована (с помощью этих конкретных кавычек именно так) так, что даже если вы случайно измените переменную среды Work позже, правильный (исходный) временный каталог будет удален, потому что переменная расширяется когда установлена ​​ловушка , а не когда ловушка срабатывает.

После вышесказанного вы можете использовать, например,

curl 'http://www.example.com/one.pdf' > "$Work/one.pdf" || exit 1
curl 'http://www.example.com/two.pdf' > "$Work/two.pdf" || exit 1

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=combined.pdf "$Work/one.pdf" "$Work/two.pdf" || exit 1

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

12
24.08.2015, 20:03
3 ответа

Если вам нужен счетчик с наименьшим общим знаменателем, который работает с /bin/sh и не зависит от расширенной подстановки параметров bash, это должно работать:

#!/bin/sh

# The command you are waiting on goes between the ( ) here
# The example below returns a non zero return code

(sleep 20 ; /bin/false) &

pid=$! ; i=0
while ps -a | awk '{print $1}' | grep -q "${pid}"
do
    c=`expr ${i} % 4`
    case ${c} in
       0) echo "/\c" ;;
       1) echo "-\c" ;;
       2) echo "\\ \b\c" ;;
       3) echo "|\c" ;;
    esac
    i=`expr ${i} + 1`
    # change the speed of the spinner by altering the 1 below
    sleep 1
    echo "\b\c"
done

# Collect the return code from the background process

wait ${pid}
ret=$?

# You can report on any errors due to a non zero return code here

exit ${ret}
3
27.01.2020, 19:54

Вот еще один причудливый спиннер, который можно использовать вот так:

spinner ping google.com
echo "ping exited with exit code $?"

spinner sleep 10
echo "sleep exited with exit code $?"

Он имеет 12 тем и выбирает одну случайным образом.

#!/bin/bash
# Shows a spinner while another command is running. Randomly picks one of 12 spinner styles.
# @args command to run (with any parameters) while showing a spinner. 
#       E.g. ‹spinner sleep 10›

function shutdown() {
  tput cnorm # reset cursor
}
trap shutdown EXIT

function cursorBack() {
  echo -en "\033[$1D"
}

function spinner() {
  # make sure we use non-unicode character type locale 
  # (that way it works for any locale as long as the font supports the characters)
  local LC_CTYPE=C

  local pid=$1 # Process Id of the previous running command

  case $(($RANDOM % 12)) in
  0)
    local spin='⠁⠂⠄⡀⢀⠠⠐⠈'
    local charwidth=3
    ;;
  1)
    local spin='-\|/'
    local charwidth=1
    ;;
  2)
    local spin="▁▂▃▄▅▆▇█▇▆▅▄▃▂▁"
    local charwidth=3
    ;;
  3)
    local spin="▉▊▋▌▍▎▏▎▍▌▋▊▉"
    local charwidth=3
    ;;
  4)
    local spin='←↖↑↗→↘↓↙'
    local charwidth=3
    ;;
  5)
    local spin='▖▘▝▗'
    local charwidth=3
    ;;
  6)
    local spin='┤┘┴└├┌┬┐'
    local charwidth=3
    ;;
  7)
    local spin='◢◣◤◥'
    local charwidth=3
    ;;
  8)
    local spin='◰◳◲◱'
    local charwidth=3
    ;;
  9)
    local spin='◴◷◶◵'
    local charwidth=3
    ;;
  10)
    local spin='◐◓◑◒'
    local charwidth=3
    ;;
  11)
    local spin='⣾⣽⣻⢿⡿⣟⣯⣷'
    local charwidth=3
    ;;
  esac

  local i=0
  tput civis # cursor invisible
  while kill -0 $pid 2>/dev/null; do
    local i=$(((i + $charwidth) % ${#spin}))
    printf "%s" "${spin:$i:$charwidth}"

    cursorBack 1
    sleep.1
  done
  tput cnorm
  wait $pid # capture exit code
  return $?
}

("$@") &

spinner $!
19
03.02.2020, 13:55

Итак, пока все приведенные выше ответы работают.. Я подумал добавить свой:

DEFAULT_SpinnerFrames=("—" "\\" "|" "/")

## @function: spinner(action, label, &spinnerFramesRef[])
##
## @description: Perform an action asynchronously and display
## spinner till action is completed
##
## @param action: The action the execute
## @param label: The label to display while waiting
## @param spinnerRef: In case you feel like a custom spinner, pass a ref to an array of strings
spinner() {
  local frameRef
  local action="${1}"
  local label="${2} "
  local spinnerRef="${3-DEFAULT_SpinnerFrames}"
  local spinnerFrames=$(eval "echo \${!${spinnerRef}[@]}")

  spinnerRun() {
    while true; do
      for frame in ${spinnerFrames[@]}; do
        frameRef="${spinnerRef}[${frame}]"
        echo "${label}${!frameRef}"
        tput cuu1 tput el
        sleep 0.2
      done
    done
    echo -e "\r"
  }

  spinnerRun &
  local spinnerPid=$!
  ${action}
  kill "${spinnerPid}"
}

гитхаб тесты

0
20.11.2020, 23:35

Теги

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