bash 또는 * NIX의 다른 쉘에서 스크립팅 할 때 몇 초 이상 걸리는 명령을 실행하는 동안 진행 표시 줄이 필요합니다.
예를 들어, 큰 파일을 복사하여 큰 tar 파일을 엽니 다.
쉘 스크립트에 진행률 표시 줄을 추가하는 방법은 무엇입니까?
bash 또는 * NIX의 다른 쉘에서 스크립팅 할 때 몇 초 이상 걸리는 명령을 실행하는 동안 진행 표시 줄이 필요합니다.
예를 들어, 큰 파일을 복사하여 큰 tar 파일을 엽니 다.
쉘 스크립트에 진행률 표시 줄을 추가하는 방법은 무엇입니까?
답변:
줄을 덮어 써서 이것을 구현할 수 있습니다. 터미널에 \r
쓰지 않고 줄의 처음으로 돌아갈 때 사용하십시오 \n
.
\n
당신이 라인을 진행 완료되면 작성 하십시오.
사용 echo -ne
:
\n
및\r
합니다.데모는 다음과 같습니다.
echo -ne '##### (33%)\r'
sleep 1
echo -ne '############# (66%)\r'
sleep 1
echo -ne '####################### (100%)\r'
echo -ne '\n'
아래 주석에서, puk은 긴 줄로 시작하여 짧은 줄을 작성하려는 경우이 "실패"를 언급합니다.이 경우 긴 줄의 길이를 덮어 써야합니다 (예 : 공백).
printf
대신에 사용하는 것입니다 echo
.
printf "#### (50%%)\r"
, 작은 따옴표로 작동하지 않으며 퍼센트 부호를 이스케이프해야합니다.
스피너를 만드는 방법에 관심이있을 수도 있습니다 .
확실한!
i=1 sp="/-\|" echo -n ' ' while true do printf "\b${sp:i++%${#sp}:1}" done
루프가 반복 될 때마다 sp 문자열에 다음 문자가 표시되고 끝에 도달 할 때 줄 바꿈됩니다. (i는 표시 할 현재 문자의 위치이고 $ {# sp}는 sp 문자열의 길이입니다).
\ b 문자열은 'backspace'문자로 대체됩니다. 또는 \ r을 사용하여 줄의 처음으로 돌아갈 수 있습니다.
속도를 늦추려면 루프 내부 (printf 뒤)에 휴면 명령을 입력하십시오.
POSIX는 다음과 같습니다.
sp='/-\|' printf ' ' while true; do printf '\b%.1s' "$sp" sp=${sp#?}${sp%???} done
많은 작업을 수행하는 루프가 이미있는 경우 각 반복 시작시 다음 함수를 호출하여 스피너를 업데이트 할 수 있습니다.
sp="/-\|" sc=0 spin() { printf "\b${sp:sc++:1}" ((sc==${#sp})) && sc=0 } endspin() { printf "\r%s\n" "$@" } until work_done; do spin some_work ... done endspin
while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done
(* sleep
의 int보다는 소수가 필요할 수 있음)
some_work ...
줄에서; 이 유용한 답변과 POSIX 준수에 중점을 둔 Adam Katz의 유용한 의견을 바탕으로 한 자세한 설명은 여기를 참조하십시오 .
\b
보다는 \r
, 그것은 것입니다 매우 라인의 시작에서 그 밖에는 작업 : while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done
-, 또는 경우 스피너 뒤에 커서를 표시 : 바람직하지 않은 것입니다printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
job=$!
)를 저장 한 후 다음과 같이 실행할 수 있습니다 while kill -0 $job 2>/dev/null;do …
.sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
일부 게시물은 명령의 진행 상황을 표시하는 방법을 보여주었습니다. 그것을 계산하기 위해, 당신은 얼마나 진행했는지 볼 필요가 있습니다. BSD 시스템에서 dd (1)와 같은 일부 명령은 SIGINFO
신호를 받아들이고 진행 상황을보고합니다. Linux 시스템에서 일부 명령은와 유사하게 응답합니다 SIGUSR1
. 이 기능이 사용 가능한 경우 입력을 파이프하여 dd
처리 된 바이트 수를 모니터 할 수 있습니다.
또는 lsof
파일 읽기 포인터의 오프셋을 확보하여 진행률을 계산하는 데 사용할 수 있습니다 . 지정된 프로세스 또는 파일 처리 진행률을 표시하는 pmonitor 라는 명령을 작성했습니다 . 그것으로 당신은 다음과 같은 일을 할 수 있습니다.
$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%
이전 버전의 Linux 및 FreeBSD 셸 스크립트가 내 블로그에 나타납니다 .
awk
놀이에 항상 그것을 사랑 해요 !
다른 날에 쓴 쉬운 진행률 표시 줄 기능이 있습니다.
#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")
# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"
}
# Variables
_start=1
# This accounts as the "totalState" variable for the ProgressBar function
_end=100
# Proof of concept
for number in $(seq ${_start} ${_end})
do
sleep 0.1
ProgressBar ${number} ${_end}
done
printf '\nFinished!\n'
printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
리눅스 명령 pv를 사용하십시오 :
스트림 중간에 있으면 크기를 알지 못하지만 속도와 총계를 제공하며 거기에서 걸리는 시간을 파악하고 피드백을 얻는 데 필요한 시간을 알 수 있습니다.
선택한 답변보다 더 섹시한 것을 찾고 있었고 내 스크립트도 마찬가지였습니다.
나는 github에 넣었다.progress-bar.sh
progress-bar() {
local duration=${1}
already_done() { for ((done=0; done<$elapsed; done++)); do printf "▇"; done }
remaining() { for ((remain=$elapsed; remain<$duration; remain++)); do printf " "; done }
percentage() { printf "| %s%%" $(( (($elapsed)*100)/($duration)*100/100 )); }
clean_line() { printf "\r"; }
for (( elapsed=1; elapsed<=$duration; elapsed++ )); do
already_done; remaining; percentage
sleep 1
clean_line
done
clean_line
}
progress-bar 100
progress-bar 100
GNU tar 에는 간단한 진행 표시 줄의 기능을 제공하는 유용한 옵션이 있습니다.
(...) 사용 가능한 다른 검사 점 작업은 'dot'(또는 '.')입니다. tar는 표준 목록 스트림에 단일 점을 인쇄하도록 지시합니다. 예 :
$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...
다음과 같은 방법으로 동일한 효과를 얻을 수 있습니다.
$ tar -c --checkpoint=.1000 /var
--checkpoint=.10
. 로 추출 할 때도 효과적입니다 tar -xz
.
비슷한 것을 보지 못했고 여기의 모든 사용자 정의 함수는 렌더링에만 중점을 둔 것처럼 보입니다.이 질문은 사소하지 않기 때문에 단계별 설명이있는 매우 간단한 POSIX 호환 솔루션입니다.
진행률 표시 줄을 렌더링하는 것은 매우 쉽습니다. 렌더링해야하는 양을 추정하는 것은 다른 문제입니다. 진행률 표시 줄을 렌더링 (애니메이션)하는 방법입니다.이 예제를 파일로 복사하여 붙여 넣어 실행할 수 있습니다.
#!/bin/sh
BAR='####################' # this is full bar, e.g. 20 chars
for i in {1..20}; do
echo -ne "\r${BAR:0:$i}" # print $i chars of $BAR from 0 position
sleep .1 # wait 100ms between "frames"
done
{1..20}
-1에서 20 사이의 값echo -n
-끝에 줄 바꿈없이 인쇄echo -e
-인쇄 중 특수 문자 해석"\r"
-캐리지 리턴, 줄의 처음으로 돌아가는 특수 문자어떤 속도로든 컨텐츠를 렌더링 할 수 있으므로이 방법은 매우 보편적입니다.
문제의 핵심은 $i
값 을 결정하는 방법, 즉 진행률 표시 줄이 표시되는 양입니다. 위의 예제 for
에서는 원리를 설명하기 위해 루프에서 증가 시켰지만 실제 응용 프로그램은 무한 루프를 사용하고 $i
각 반복 에서 변수를 계산합니다 . 상기 계산을하려면 다음 성분이 필요합니다.
의 경우 cp
그 소스 파일과 대상 파일의 크기의 크기를해야합니다 :
#!/bin/sh
$src=/path/to/source/file
$tgt=/path/to/target/file
cp "$src" "$tgt" & # the & forks the `cp` process so the rest
# of the code runs without waiting (async)
BAR='####################'
src_size=$(stat -c%s "$src") # how much there is to do
while true; do
tgt_size=$(stat -c%s "$tgt") # how much has been done so far
i=$(( $tgt_size * 20 / $src_size ))
echo -ne "\r${BAR:0:$i}"
if [ $tgt_size == $src_size ]; then
echo "" # add a new line at the end
break; # break the loop
fi
sleep .1
done
stat
-파일 통계 확인-c
-형식화 된 값을 반환%s
- 총합 크기파일 압축 해제와 같은 작업의 경우 소스 크기를 계산하는 것이 약간 더 어렵지만 압축되지 않은 파일의 크기를 얻는 것만 큼 쉽습니다.
#!/bin/sh
src_size=$(gzip -l "$src" | tail -n1 | tr -s ' ' | cut -d' ' -f3)
gzip -l
-우편 아카이브에 대한 정보 표시tail -n1
-바닥에서 한 줄로 작업tr -s ' '
-여러 공간을 하나로 번역하십시오 (압착하십시오).cut -d' ' -f3
-공백으로 구분 된 세 번째 열을 자릅니다.그래도 문제의 고기가 있습니다. 이 솔루션은 점점 덜 일반적입니다. 실제 진행 상황에 대한 모든 계산은 시각화하려는 도메인에 밀접하게 바인딩되어 있습니다. 단일 파일 작업, 타이머 카운트 다운, 디렉토리의 파일 수 증가, 여러 파일에서의 작업 등입니다. 재사용 할 수 없습니다. 재사용 가능한 유일한 부분은 진행률 표시 줄 렌더링입니다. 이를 재사용하려면 추상화하고 파일 (예 :)에 저장 /usr/lib/progress_bar.sh
한 다음 도메인에 특정한 입력 값을 계산하는 함수를 정의해야합니다. 이것은 일반 코드가 어떻게 생겼는지 보여줍니다 $BAR
.
#!/bin/sh
BAR_length=50
BAR_character='#'
BAR=$(printf "%${BAR_length}s" | tr ' ' $BAR_character)
work_todo=$(get_work_todo) # how much there is to do
while true; do
work_done=$(get_work_done) # how much has been done so far
i=$(( $work_done * $BAR_length / $work_todo ))
echo -ne "\r${BAR:0:$i}"
if [ $work_done == $work_todo ]; then
echo ""
break;
fi
sleep .1
done
printf
-주어진 형식으로 물건을 인쇄하기위한 내장printf '%50s'
-아무것도 인쇄하지 않고 50 칸으로 채 웁니다.tr ' ' '#'
-모든 공간을 해시 표시로 변환그리고 이것이 당신이 그것을 사용하는 방법입니다 :
#!/bin/sh
src=/path/to/source/file
tgt=/path/to/target/file
function get_work_todo() {
echo $(stat -c%s "$src")
}
function get_work_done() {
[ -e "$tgt" ] && # if target file exists
echo $(stat -c%s "$tgt") || # echo its size, else
echo 0 # echo zero
}
cp "$src" "$tgt" & # copy in the background
source /usr/lib/progress_bar.sh # execute the progress bar
분명히 그것은 함수에 싸여 파이프 스트림과 함께 작동하도록 다시 쓰여지고 독에 관계없이 다른 언어로 다시 쓰여질 수 있습니다.
편집 : 업데이트 된 버전은 내 github 페이지를 확인 하십시오.
이 질문에 대한 답변에 만족하지 않았습니다. 내가 개인적으로 찾고 있던 것은 APT에서 볼 수있는 멋진 진행률 표시 줄이었습니다.
나는 APT에 대한 C 소스 코드를 보았고 bash에 대한 동등한 코드를 작성하기로 결정했다.
이 진행률 표시 줄은 터미널 하단에 잘 유지되며 터미널로 전송되는 출력을 방해하지 않습니다.
막대는 현재 100 자 너비로 고정되어 있습니다. 터미널의 크기에 맞게 확장하려면이 작업도 상당히 쉽습니다 (github 페이지의 업데이트 된 버전이이를 잘 처리합니다).
스크립트를 여기에 게시하겠습니다. 사용 예 :
source ./progress_bar.sh
echo "This is some output"
setup_scroll_area
sleep 1
echo "This is some output 2"
draw_progress_bar 10
sleep 1
echo "This is some output 3"
draw_progress_bar 50
sleep 1
echo "This is some output 4"
draw_progress_bar 90
sleep 1
echo "This is some output 5"
destroy_scroll_area
스크립트 (대신 github의 버전을 대신 권장합니다) :
#!/bin/bash
# This code was inspired by the open source C code of the APT progress bar
# http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/apt/trusty/view/head:/apt-pkg/install-progress.cc#L233
#
# Usage:
# Source this script
# setup_scroll_area
# draw_progress_bar 10
# draw_progress_bar 90
# destroy_scroll_area
#
CODE_SAVE_CURSOR="\033[s"
CODE_RESTORE_CURSOR="\033[u"
CODE_CURSOR_IN_SCROLL_AREA="\033[1A"
COLOR_FG="\e[30m"
COLOR_BG="\e[42m"
RESTORE_FG="\e[39m"
RESTORE_BG="\e[49m"
function setup_scroll_area() {
lines=$(tput lines)
let lines=$lines-1
# Scroll down a bit to avoid visual glitch when the screen area shrinks by one row
echo -en "\n"
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Set scroll region (this will place the cursor in the top left)
echo -en "\033[0;${lines}r"
# Restore cursor but ensure its inside the scrolling area
echo -en "$CODE_RESTORE_CURSOR"
echo -en "$CODE_CURSOR_IN_SCROLL_AREA"
# Start empty progress bar
draw_progress_bar 0
}
function destroy_scroll_area() {
lines=$(tput lines)
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Set scroll region (this will place the cursor in the top left)
echo -en "\033[0;${lines}r"
# Restore cursor but ensure its inside the scrolling area
echo -en "$CODE_RESTORE_CURSOR"
echo -en "$CODE_CURSOR_IN_SCROLL_AREA"
# We are done so clear the scroll bar
clear_progress_bar
# Scroll down a bit to avoid visual glitch when the screen area grows by one row
echo -en "\n\n"
}
function draw_progress_bar() {
percentage=$1
lines=$(tput lines)
let lines=$lines
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Move cursor position to last row
echo -en "\033[${lines};0f"
# Clear progress bar
tput el
# Draw progress bar
print_bar_text $percentage
# Restore cursor position
echo -en "$CODE_RESTORE_CURSOR"
}
function clear_progress_bar() {
lines=$(tput lines)
let lines=$lines
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Move cursor position to last row
echo -en "\033[${lines};0f"
# clear progress bar
tput el
# Restore cursor position
echo -en "$CODE_RESTORE_CURSOR"
}
function print_bar_text() {
local percentage=$1
# Prepare progress bar
let remainder=100-$percentage
progress_bar=$(echo -ne "["; echo -en "${COLOR_FG}${COLOR_BG}"; printf_new "#" $percentage; echo -en "${RESTORE_FG}${RESTORE_BG}"; printf_new "." $remainder; echo -ne "]");
# Print progress bar
if [ $1 -gt 99 ]
then
echo -ne "${progress_bar}"
else
echo -ne "${progress_bar}"
fi
}
printf_new() {
str=$1
num=$2
v=$(printf "%-${num}s" "$str")
echo -ne "${v// /$str}"
}
이를 통해 명령이 여전히 실행 중임을 시각화 할 수 있습니다.
while :;do echo -n .;sleep 1;done &
trap "kill $!" EXIT #Die with parent if we die prematurely
tar zxf packages.tar.gz; # or any other command here
kill $! && trap " " EXIT #Kill the loop and unset the trap or else the pid might get reassigned and we might end up killing a completely different process
백그라운드에서 실행되고 "."를 에코 하는 무한 while 루프 가 생성됩니다 . 매 초. .
셸에 표시 됩니다. tar
명령 또는 원하는 명령을 실행하십시오 . 다음 실행하는 명령이 완료가되면 죽일 수 는 IS - 백그라운드에서 실행중인 마지막 작업 루프 동안 무한 .
파일 업로드
[##################################################] 100% (137921 / 137921 bytes)
작업이 완료되기를 기다리는 중
[######################### ] 50% (15 / 30 seconds)
스크립트에 복사하여 붙여 넣기 만하면됩니다. 작동하기 위해 다른 것이 필요하지 않습니다.
PROGRESS_BAR_WIDTH=50 # progress bar length in characters
draw_progress_bar() {
# Arguments: current value, max value, unit of measurement (optional)
local __value=$1
local __max=$2
local __unit=${3:-""} # if unit is not supplied, do not display it
# Calculate percentage
if (( $__max < 1 )); then __max=1; fi # anti zero division protection
local __percentage=$(( 100 - ($__max*100 - $__value*100) / $__max ))
# Rescale the bar according to the progress bar width
local __num_bar=$(( $__percentage * $PROGRESS_BAR_WIDTH / 100 ))
# Draw progress bar
printf "["
for b in $(seq 1 $__num_bar); do printf "#"; done
for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - $__num_bar ))); do printf " "; done
printf "] $__percentage%% ($__value / $__max $__unit)\r"
}
여기에서 파일을 업로드하고 각 반복마다 진행률 표시 줄을 다시 그립니다. 최대 값과 현재 값의 두 가지 값을 얻을 수있는 한 실제로 수행되는 작업은 중요하지 않습니다.
아래 예에서 최대 값은 file_size
이며 현재 값은 일부 함수에 의해 제공되며 호출 uploaded_bytes
됩니다.
# Uploading a file
file_size=137921
while true; do
# Get current value of uploaded bytes
uploaded_bytes=$(some_function_that_reports_progress)
# Draw a progress bar
draw_progress_bar $uploaded_bytes $file_size "bytes"
# Check if we reached 100%
if [ $uploaded_bytes == $file_size ]; then break; fi
sleep 1 # Wait before redrawing
done
# Go to the newline at the end of upload
printf "\n"
대부분의 유닉스 명령어는 당신이 할 수있는 직접적인 피드백을 제공하지 않습니다. 일부는 stdout 또는 stderr에서 사용할 수있는 출력을 제공합니다.
tar와 같은 경우 -v 스위치를 사용하여 읽은 각 줄에 대해 작은 애니메이션을 업데이트하는 프로그램으로 출력을 파이프 할 수 있습니다. tar는 파일 목록을 작성함에 따라 프로그램에서 애니메이션을 업데이트 할 수 있습니다. 완료율을 달성하려면 파일 수를 알고 행 수를 계산해야합니다.
cp는 내가 아는 한 이런 종류의 출력을 제공하지 않습니다. cp의 진행 상황을 모니터링하려면 소스 및 대상 파일을 모니터링하고 대상의 크기를 확인해야합니다. 파일 크기를 얻기 위해 stat (2) 시스템 호출을 사용하여 작은 c 프로그램을 작성할 수 있습니다. 소스 크기를 읽은 다음 대상 파일을 폴링하고 현재까지 기록 된 파일 크기를 기준으로 완료율 (%)을 업데이트합니다.
내 솔루션에는 현재 압축되지 않은 타르볼의 백분율이 표시됩니다. 2GB 루트 파일 시스템 이미지를 작성할 때 이것을 사용합니다. 당신은 정말로 이런 것들에 대한 진행 표시 줄이 필요합니다. 내가하는 것은 gzip --list
tarball의 전체 압축되지 않은 크기를 얻는 데 사용 하는 것입니다
. 그로부터 파일을 100 부분으로 나누는 데 필요한 차단 계수를 계산합니다. 마지막으로 각 블록에 대한 검사 점 메시지를 인쇄합니다. 2GB 파일의 경우 약 10MB의 블록이 제공됩니다. 그것이 너무 크면 BLOCKING_FACTOR를 10 또는 100으로 나눌 수 있지만 백분율로 예쁜 출력을 인쇄하는 것이 더 어렵습니다.
Bash를 사용한다고 가정하면 다음 쉘 기능을 사용할 수 있습니다
untar_progress ()
{
TARBALL=$1
BLOCKING_FACTOR=$(gzip --list ${TARBALL} |
perl -MPOSIX -ane '$.==2 && print ceil $F[1]/50688')
tar --blocking-factor=${BLOCKING_FACTOR} --checkpoint=1 \
--checkpoint-action='ttyout=Wrote %u% \r' -zxf ${TARBALL}
}
우선 모든 막대가 유일한 파이프 진행 미터는 아닙니다. 다른 것 (아마도 더 알려질 수도 있음)은 pv (파이프 뷰어)입니다.
두 번째로 bar 및 pv는 예를 들어 다음과 같이 사용할 수 있습니다.
$ bar file1 | wc -l
$ pv file1 | wc -l
또는:
$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l
copy file1 file2와 같이 인수로 주어진 파일로 작업하는 명령에서 bar 및 pv를 사용하려는 경우 유용한 트릭은 프로세스 대체 를 사용 하는 것입니다 .
$ copy <(bar file1) file2
$ copy <(pv file1) file2
프로세스 대체는 임시 fifo 파이프 파일 / dev / fd /를 작성하고 실행 된 프로세스 (괄호 안의)에서 stdout을이 파이프를 통해 연결하고 복사하면 일반 파일처럼 볼 수 있습니다 (한 예외는 읽을 수만 있음) 전달).
최신 정보:
bar 명령 자체는 복사도 가능합니다. 남자 바 후 :
bar --in-file /dev/rmt/1cbn --out-file \
tape-restore.tar --size 2.4g --buffer-size 64k
그러나 프로세스 대체는 더 일반적인 방법입니다. 그것은 cp 프로그램 자체를 사용합니다.
--gauge 매개 변수 와 함께 대화 상자 를 사용하는 것을 선호합니다 . .deb 패키지 설치 및 많은 배포판의 기타 기본 구성 항목에서 매우 자주 사용됩니다. 따라서 휠을 다시 발명 할 필요가 없습니다 ... 다시
1에서 100 @stdin까지 int 값을 입력하십시오. 하나의 기본적이고 어리석은 예 :
for a in {1..100}; do sleep .1s; echo $a| dialog --gauge "waiting" 7 30; done
요리 목적 으로이 / bin / Wait 파일 (chmod u + x perms 포함)이 있습니다 : P
#!/bin/bash
INIT=`/bin/date +%s`
NOW=$INIT
FUTURE=`/bin/date -d "$1" +%s`
[ $FUTURE -a $FUTURE -eq $FUTURE ] || exit
DIFF=`echo "$FUTURE - $INIT"|bc -l`
while [ $INIT -le $FUTURE -a $NOW -lt $FUTURE ]; do
NOW=`/bin/date +%s`
STEP=`echo "$NOW - $INIT"|bc -l`
SLEFT=`echo "$FUTURE - $NOW"|bc -l`
MLEFT=`echo "scale=2;$SLEFT/60"|bc -l`
TEXT="$SLEFT seconds left ($MLEFT minutes)";
TITLE="Waiting $1: $2"
sleep 1s
PTG=`echo "scale=0;$STEP * 100 / $DIFF"|bc -l`
echo $PTG| dialog --title "$TITLE" --gauge "$TEXT" 7 72
done
if [ "$2" == "" ]; then msg="Espera terminada: $1";audio="Listo";
else msg=$2;audio=$2;fi
/usr/bin/notify-send --icon=stock_appointment-reminder-excl "$msg"
espeak -v spanish "$audio"
그래서 나는 넣을 수 있습니다 :
Wait "34 min" "warm up the oven"
또는
Wait "dec 31" "happy new year"
나를 위해 사용하기 가장 쉽고 지금까지 가장 잘 보이는 것은 명령 pv
이거나 bar
이미 쓴 사람과 같습니다.
예를 들어 다음과 같이 전체 드라이브를 백업해야합니다. dd
일반적으로 사용 dd if="$input_drive_path" of="$output_file_path"
으로 pv
당신과 같이 그것을 만들 수 있습니다 :
dd if="$input_drive_path" | pv | dd of="$output_file_path"
진행 상황은 다음과 같이 직접 진행됩니다 STDOUT
.
7.46GB 0:33:40 [3.78MB/s] [ <=> ]
완료되면 요약이 나타납니다.
15654912+0 records in
15654912+0 records out
8015314944 bytes (8.0 GB) copied, 2020.49 s, 4.0 MB/s
pv
하거나 bar
시각화 할 수 있습니까 ?
많은 답변은 인쇄 명령을 작성하는 방법을 설명합니다 '\r' + $some_sort_of_progress_msg
. 문제는 때때로 초당 수백 개의 업데이트를 인쇄하면 프로세스 속도가 느려진다는 것입니다.
그러나 프로세스에서 출력을 생성하는 경우 (예 : 7z a -r newZipFile myFolder
압축 할 때 각 파일 이름이 출력 됨) 더 간단하고 빠르고 고통스럽지 않고 사용자 정의 할 수있는 솔루션이 존재합니다.
파이썬 모듈을 설치합니다 tqdm
.
$ sudo pip install tqdm
$ # now have fun
$ 7z a -r -bd newZipFile myFolder | tqdm >> /dev/null
$ # if we know the expected total, we can have a bar!
$ 7z a -r -bd newZipFile myFolder | grep -o Compressing | tqdm --total $(find myFolder -type f | wc -l) >> /dev/null
도움말 : tqdm -h
. 더 많은 옵션을 사용하는 예 :
$ find / -name '*.py' -exec cat \{} \; | tqdm --unit loc --unit_scale True | wc -l
보너스 tqdm
로 파이썬 코드로 이터 러블을 래핑 하는 데 사용할 수도 있습니다 .
tqdm
STDOUT을 wc -l
파이프 로 통과시키는 것 같습니다 . 아마도 그것을 피하고 싶을 것입니다.
tqdm
이 진행 상태를 표시 합니다 . 이 경우 whould 는 포함되지 않은 것과 동일한 입력을받습니다 . STDERR
STDIN
STDOUT
wc -l
tqdm
Edouard Lopez의 작업을 기반으로 화면 크기에 맞는 진행률 표시 줄을 만들었습니다. 확인 해봐.
Git Hub 에도 게시되어 있습니다.
#!/bin/bash
#
# Progress bar by Adriano Pinaffo
# Available at https://github.com/adriano-pinaffo/progressbar.sh
# Inspired on work by Edouard Lopez (https://github.com/edouard-lopez/progress-bar.sh)
# Version 1.0
# Date April, 28th 2017
function error {
echo "Usage: $0 [SECONDS]"
case $1 in
1) echo "Pass one argument only"
exit 1
;;
2) echo "Parameter must be a number"
exit 2
;;
*) echo "Unknown error"
exit 999
esac
}
[[ $# -ne 1 ]] && error 1
[[ $1 =~ ^[0-9]+$ ]] || error 2
duration=${1}
barsize=$((`tput cols` - 7))
unity=$(($barsize / $duration))
increment=$(($barsize%$duration))
skip=$(($duration/($duration-$increment)))
curr_bar=0
prev_bar=
for (( elapsed=1; elapsed<=$duration; elapsed++ ))
do
# Elapsed
prev_bar=$curr_bar
let curr_bar+=$unity
[[ $increment -eq 0 ]] || {
[[ $skip -eq 1 ]] &&
{ [[ $(($elapsed%($duration/$increment))) -eq 0 ]] && let curr_bar++; } ||
{ [[ $(($elapsed%$skip)) -ne 0 ]] && let curr_bar++; }
}
[[ $elapsed -eq 1 && $increment -eq 1 && $skip -ne 1 ]] && let curr_bar++
[[ $(($barsize-$curr_bar)) -eq 1 ]] && let curr_bar++
[[ $curr_bar -lt $barsize ]] || curr_bar=$barsize
for (( filled=0; filled<=$curr_bar; filled++ )); do
printf "▇"
done
# Remaining
for (( remain=$curr_bar; remain<$barsize; remain++ )); do
printf " "
done
# Percentage
printf "| %s%%" $(( ($elapsed*100)/$duration))
# Return
sleep 1
printf "\r"
done
printf "\n"
exit 0
즐겨
이것은 gnome zenity를 사용하는 경우에만 적용됩니다. Zenity는 스크립트를 bash하기위한 훌륭한 기본 인터페이스를 제공합니다. https://help.gnome.org/users/zenity/stable/
Zenity 진행률 표시 줄 예 :
#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
--title="Update System Logs" \
--text="Scanning mail logs..." \
--percentage=0
if [ "$?" = -1 ] ; then
zenity --error \
--text="Update canceled."
fi
char 스크립트 를 반복하기 위해 쉘 스크립트에서 반복되는 문자 문자열 만들기 의 대답을 사용했습니다 . 진행률 표시 줄을 표시 해야하는 스크립트 (예 : 많은 파일을 통과하지만 큰 tar 파일 또는 복사 작업에는 유용하지 않은 루프)에 대해 상대적으로 작은 bash 버전 이 두 개 있습니다. 더 빠른 것은 두 개의 기능으로 구성되는데, 하나는 바 표시를 위해 문자열을 준비하는 것입니다.
preparebar() {
# $1 - bar length
# $2 - bar char
barlen=$1
barspaces=$(printf "%*s" "$1")
barchars=$(printf "%*s" "$1" | tr ' ' "$2")
}
하나는 진행률 표시 줄을 표시합니다.
progressbar() {
# $1 - number (-1 for clearing the bar)
# $2 - max number
if [ $1 -eq -1 ]; then
printf "\r $barspaces\r"
else
barch=$(($1*barlen/$2))
barsp=$((barlen-barch))
printf "\r[%.${barch}s%.${barsp}s]\r" "$barchars" "$barspaces"
fi
}
다음과 같이 사용할 수 있습니다.
preparebar 50 "#"
즉, 50 개의 "#"문자로 바를위한 문자열을 준비한 후 다음을 수행합니다.
progressbar 35 80
35/80 비율에 해당하는 "#"문자 수가 표시됩니다.
[##################### ]
이 기능은 사용자 (또는 다른 프로그램)가 줄 바꿈을 인쇄 할 때까지 동일한 줄에 계속 막대를 표시합니다. -1을 첫 번째 매개 변수로 입력하면 막대가 지워집니다.
progressbar -1 80
느린 버전은 모두 하나의 기능에 있습니다.
progressbar() {
# $1 - number
# $2 - max number
# $3 - number of '#' characters
if [ $1 -eq -1 ]; then
printf "\r %*s\r" "$3"
else
i=$(($1*$3/$2))
j=$(($3-i))
printf "\r[%*s" "$i" | tr ' ' '#'
printf "%*s]\r" "$j"
fi
}
(위와 동일한 예)와 같이 사용할 수 있습니다.
progressbar 35 80 50
stderr에 진행률 표시 줄이 필요한 경우 >&2
각 printf 명령 끝에 추가하십시오 .
활동 진행률을 나타내려면 다음 명령을 시도하십시오.
while true; do sleep 0.25 && echo -ne "\r\\" && sleep 0.25 && echo -ne "\r|" && sleep 0.25 && echo -ne "\r/" && sleep 0.25 && echo -ne "\r-"; done;
또는
while true; do sleep 0.25 && echo -ne "\rActivity: \\" && sleep 0.25 && echo -ne "\rActivity: |" && sleep 0.25 && echo -ne "\rActivity: /" && sleep 0.25 && echo -ne "\rActivity: -"; done;
또는
while true; do sleep 0.25 && echo -ne "\r" && sleep 0.25 && echo -ne "\r>" && sleep 0.25 && echo -ne "\r>>" && sleep 0.25 && echo -ne "\r>>>"; sleep 0.25 && echo -ne "\r>>>>"; done;
또는
while true; do sleep .25 && echo -ne "\r:Active:" && sleep .25 && echo -ne "\r:aCtive:" && sleep .25 && echo -ne "\r:acTive:" && sleep .25 && echo -ne "\r:actIve:" && sleep .25 && echo -ne "\r:actiVe:" && sleep .25 && echo -ne "\r:activE:"; done;
while 루프 내에서 플래그 / 변수를 사용 하여 값 / 진행 상황을 확인하고 표시 할 수 있습니다 .
위에 나열된 제안을 사용하여 자체 진행률 표시 줄을 구현하기로 결정했습니다.
#!/usr/bin/env bash
main() {
for (( i = 0; i <= 100; i=$i + 1)); do
progress_bar "$i"
sleep 0.1;
done
progress_bar "done"
exit 0
}
progress_bar() {
if [ "$1" == "done" ]; then
spinner="X"
percent_done="100"
progress_message="Done!"
new_line="\n"
else
spinner='/-\|'
percent_done="${1:-0}"
progress_message="$percent_done %"
fi
percent_none="$(( 100 - $percent_done ))"
[ "$percent_done" -gt 0 ] && local done_bar="$(printf '#%.0s' $(seq -s ' ' 1 $percent_done))"
[ "$percent_none" -gt 0 ] && local none_bar="$(printf '~%.0s' $(seq -s ' ' 1 $percent_none))"
# print the progress bar to the screen
printf "\r Progress: [%s%s] %s %s${new_line}" \
"$done_bar" \
"$none_bar" \
"${spinner:x++%${#spinner}:1}" \
"$progress_message"
}
main "$@"
percent_none="$(( 100 - "$percent_done" ))"
을percent_none="$(( 100 - $percent_done))"
임베디드 시스템을 위해 순수한 쉘 버전을 사용했습니다.
/ usr / bin / dd의 SIGUSR1 신호 처리 기능.
기본적으로 'kill SIGUSR1 $ (pid_of_running_dd_process)'를 보내면 처리량 속도와 전송 된 양의 요약이 출력됩니다.
dd를 백그라운드로 업데이트 한 다음 정기적으로 업데이트를 요청하고 이전의 ftp 클라이언트와 같은 해시 틱을 생성합니다.
scp와 같은 비표준 친화적 프로그램의 대상으로 / dev / stdout 사용
결과적으로 모든 파일 전송 작업을 수행하고 모든 X 바이트에 대해 해시 마크를 얻는 구식 FTP '해시'출력과 같은 진행 업데이트를 얻을 수 있습니다.
이것은 프로덕션 품질 코드는 아니지만 아이디어를 얻습니다. 귀엽다고 생각합니다.
가치가있는 경우 실제 바이트 수는 해시 수에 올바르게 반영되지 않을 수 있습니다. 반올림 문제에 따라 하나 이상이있을 수 있습니다. 이것을 테스트 스크립트의 일부로 사용하지 마십시오. 눈에 띄는 사탕입니다. 그리고 그렇습니다, 나는 이것이 매우 비효율적이라는 것을 알고 있습니다-그것은 셸 스크립트이며 사과하지 않습니다.
끝에 wget, scp 및 tftp가 제공되는 예제. 데이터를 방출하는 모든 것이 작동해야합니다. 친숙하지 않은 프로그램에는 / dev / stdout을 사용하십시오.
#!/bin/sh
#
# Copyright (C) Nathan Ramella (nar+progress-script@remix.net) 2010
# LGPLv2 license
# If you use this, send me an email to say thanks and let me know what your product
# is so I can tell all my friends I'm a big man on the internet!
progress_filter() {
local START=$(date +"%s")
local SIZE=1
local DURATION=1
local BLKSZ=51200
local TMPFILE=/tmp/tmpfile
local PROGRESS=/tmp/tftp.progress
local BYTES_LAST_CYCLE=0
local BYTES_THIS_CYCLE=0
rm -f ${PROGRESS}
dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
| grep --line-buffered -E '[[:digit:]]* bytes' \
| awk '{ print $1 }' >> ${PROGRESS} &
# Loop while the 'dd' exists. It would be 'more better' if we
# actually looked for the specific child ID of the running
# process by identifying which child process it was. If someone
# else is running dd, it will mess things up.
# My PID handling is dumb, it assumes you only have one running dd on
# the system, this should be fixed to just get the PID of the child
# process from the shell.
while [ $(pidof dd) -gt 1 ]; do
# PROTIP: You can sleep partial seconds (at least on linux)
sleep .5
# Force dd to update us on it's progress (which gets
# redirected to $PROGRESS file.
#
# dumb pid handling again
pkill -USR1 dd
local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))
# Don't print anything unless we've got 1 block or more.
# This allows for stdin/stderr interactions to occur
# without printing a hash erroneously.
# Also makes it possible for you to background 'scp',
# but still use the /dev/stdout trick _even_ if scp
# (inevitably) asks for a password.
#
# Fancy!
if [ $XFER_BLKS -gt 0 ]; then
printf "#%0.s" $(seq 0 $XFER_BLKS)
BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
fi
done
local SIZE=$(stat -c"%s" $TMPFILE)
local NOW=$(date +"%s")
if [ $NOW -eq 0 ]; then
NOW=1
fi
local DURATION=$(($NOW-$START))
local BYTES_PER_SECOND=$(( SIZE / DURATION ))
local KBPS=$((SIZE/DURATION/1024))
local MD5=$(md5sum $TMPFILE | awk '{ print $1 }')
# This function prints out ugly stuff suitable for eval()
# rather than a pretty string. This makes it a bit more
# flexible if you have a custom format (or dare I say, locale?)
printf "\nDURATION=%d\nBYTES=%d\nKBPS=%f\nMD5=%s\n" \
$DURATION \
$SIZE \
$KBPS \
$MD5
}
예 :
echo "wget"
wget -q -O /dev/stdout http://www.blah.com/somefile.zip | progress_filter
echo "tftp"
tftp -l /dev/stdout -g -r something/firmware.bin 192.168.1.1 | progress_filter
echo "scp"
scp user@192.168.1.1:~/myfile.tar /dev/stdout | progress_filter
시간 진행률 표시 줄을 표시 해야하는 경우 (표시 시간을 미리 알고) 다음과 같이 Python을 사용할 수 있습니다.
#!/bin/python
from time import sleep
import sys
if len(sys.argv) != 3:
print "Usage:", sys.argv[0], "<total_time>", "<progressbar_size>"
exit()
TOTTIME=float(sys.argv[1])
BARSIZE=float(sys.argv[2])
PERCRATE=100.0/TOTTIME
BARRATE=BARSIZE/TOTTIME
for i in range(int(TOTTIME)+1):
sys.stdout.write('\r')
s = "[%-"+str(int(BARSIZE))+"s] %d%% "
sys.stdout.write(s % ('='*int(BARRATE*i), int(PERCRATE*i)))
sys.stdout.flush()
SLEEPTIME = 1.0
if i == int(TOTTIME): SLEEPTIME = 0.1
sleep(SLEEPTIME)
print ""
그런 다음 Python 스크립트를로 저장했다고 가정하면 progressbar.py
다음 명령을 실행하여 bash 스크립트에서 진행률 표시 줄을 표시 할 수 있습니다.
python progressbar.py 10 50
진행률 막대가 크기로 표시됩니다. 50
문자와 10
몇 초 동안 "실행 중" 됩니다.
나는 공포에 의해 제공된 답변을 바탕으로
RMAN 복원 진행률을 검색하기 위해 Oracle 데이터베이스에 연결합니다.
#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")
# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"
}
function rman_check {
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
select
round((sofar/totalwork) * 100,0) pct_done
from
v\$session_longops
where
totalwork > sofar
AND
opname NOT LIKE '%aggregate%'
AND
opname like 'RMAN%';
exit
EOF
}
# Variables
_start=1
# This accounts as the "totalState" variable for the ProgressBar function
_end=100
_rman_progress=$(rman_check)
#echo ${_rman_progress}
# Proof of concept
#for number in $(seq ${_start} ${_end})
while [ ${_rman_progress} -lt 100 ]
do
for number in _rman_progress
do
sleep 10
ProgressBar ${number} ${_end}
done
_rman_progress=$(rman_check)
done
printf '\nFinished!\n'
#!/bin/bash
function progress_bar() {
bar=""
total=10
[[ -z $1 ]] && input=0 || input=${1}
x="##"
for i in `seq 1 10`; do
if [ $i -le $input ] ;then
bar=$bar$x
else
bar="$bar "
fi
done
#pct=$((200*$input/$total % 2 + 100*$input/$total))
pct=$(($input*10))
echo -ne "Progress : [ ${bar} ] (${pct}%) \r"
sleep 1
if [ $input -eq 10 ] ;then
echo -ne '\n'
fi
}
막대 수에 대해 1-10과 같은 스케일로 이것을 그리는 함수를 만들 수 있습니다.
progress_bar 1
echo "doing something ..."
progress_bar 2
echo "doing something ..."
progress_bar 3
echo "doing something ..."
progress_bar 8
echo "doing something ..."
progress_bar 10
#!/bin/bash
tot=$(wc -c /proc/$$/fd/255 | awk '/ /{print $1}')
now() {
echo $(( 100* ($(awk '/^pos:/{print $2}' < /proc/$$/fdinfo/255)-166) / (tot-166) )) "%"
}
now;
now;
now;
now;
now;
now;
now;
now;
now;
산출:
0 %
12 %
25 %
37 %
50 %
62 %
75 %
87 %
100 %
참고 : 255 대신 1을 입력하면 표준 입력을 모니터링하고 2를 표준 출력으로 모니터링합니다 (그러나 소스를 수정하여 "tot"를 투영 된 출력 파일 크기로 설정해야 함)