เมื่อสคริปต์ใน 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 เพื่อกลับไปที่จุดเริ่มต้นของบรรทัด
หากคุณต้องการให้มันช้าลงให้ใส่คำสั่ง sleep ภายในลูป (หลังจาก 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
อาจต้องใช้ ints มากกว่าทศนิยม)
some_work ...
บรรทัดด้านบน; การอภิปรายรายละเอียดเพิ่มเติมที่สร้างขึ้นบนคำตอบนี้เป็นประโยชน์และแสดงความคิดเห็นที่เป็นประโยชน์อดัมแคทซ์ - ให้ความสำคัญกับการปฏิบัติตาม POSIX - การสามารถพบได้ที่นี่
\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
สัญญาณและจะรายงานความคืบหน้า 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'
หรือขัดขวางได้จาก
https://github.com/fearside/ProgressBar/
printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
ใช้คำสั่ง linux pv:
ไม่ทราบขนาดถ้าอยู่กลางสตรีม แต่ให้ความเร็วและผลรวมและจากตรงนั้นคุณสามารถทราบได้ว่าควรใช้เวลานานแค่ไหนและรับความคิดเห็นเพื่อให้คุณรู้ว่ามันไม่ได้แขวน
ฉันกำลังมองหาบางสิ่งที่เซ็กซี่มากกว่าคำตอบที่เลือกไว้ดังนั้นสคริปต์ของฉันเองก็เช่นกัน
ฉันใส่มันลงบนGitHubprogress-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
tar GNUมีตัวเลือกที่มีประโยชน์ซึ่งให้การทำงานของแถบความคืบหน้าอย่างง่าย
(... ) การกระทำอื่น ๆ ของจุดตรวจสอบที่มีคือ 'dot' (หรือ '.') มันสั่งให้ tar พิมพ์จุดเดียวบนสตรีมรายการมาตรฐานเช่น:
$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...
อาจได้รับผลกระทบเดียวกันโดย:
$ tar -c --checkpoint=.1000 /var
--checkpoint=.10
ลง tar -xz
นอกจากนี้ยังใช้งานได้ดีเมื่อมีการแยก
วิธีที่ง่ายกว่าที่ใช้กับระบบของฉันโดยใช้ยูทิลิตี้ pipeview (pv)
srcdir=$1
outfile=$2
tar -Ocf - $srcdir | pv -i 1 -w 50 -berps `du -bs $srcdir | awk '{print $1}'` | 7za a -si $outfile
ไม่เคยเห็นอะไรที่คล้ายกันและฟังก์ชั่นที่กำหนดเองทั้งหมดที่นี่ดูเหมือนจะมุ่งเน้นที่การแสดงผลเพียงอย่างเดียวดังนั้น ... โซลูชันที่ใช้งานง่าย 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 ถึง 20echo -n
- พิมพ์โดยไม่ต้องขึ้นบรรทัดใหม่ในตอนท้ายecho -e
- ตีความตัวละครพิเศษในขณะที่พิมพ์"\r"
- carriage return, ถ่านพิเศษเพื่อกลับไปที่จุดเริ่มต้นของบรรทัดคุณสามารถทำให้มันแสดงผลเนื้อหาได้ทุกความเร็วดังนั้นวิธีนี้จึงเป็นสากลมากเช่นมักจะใช้สำหรับการแสดงภาพ "แฮ็ค" ในภาพยนตร์ที่โง่เง่าไม่ล้อเล่น
เนื้อของปัญหาคือวิธีการกำหนด$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
- แสดงข้อมูลเกี่ยวกับไฟล์ ziptail -n1
- ทำงานกับ 1 บรรทัดจากด้านล่างtr -s ' '
- แปลหลายช่องว่างเป็นหนึ่ง (บีบพวกเขา)cut -d' ' -f3
- ตัดคอลัมน์ที่คั่นด้วยช่องว่างที่ 3แต่นี่คือเนื้อของปัญหา วิธีนี้มีน้อยลงและน้อยลง การคำนวณความคืบหน้าจริงทั้งหมดจะถูกผูกไว้กับโดเมนที่คุณพยายามเห็นภาพอย่างชัดเจนไม่ว่าจะเป็นการดำเนินการไฟล์เดียวการนับเวลาถอยหลังจำนวนไฟล์ที่เพิ่มขึ้นในไดเรกทอรีการทำงานกับไฟล์หลาย ๆ ไฟล์ ฯลฯ ไม่สามารถนำกลับมาใช้ใหม่ได้ ส่วนที่นำมาใช้ซ้ำได้เท่านั้นคือการสร้างแถบความคืบหน้า ในการใช้ซ้ำคุณต้องทำให้เป็นนามธรรมและบันทึกในไฟล์ (เช่น/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
- builtin สำหรับการพิมพ์สิ่งต่าง ๆ ในรูปแบบที่กำหนด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
เห็นได้ชัดว่ามันสามารถห่อหุ้มด้วยฟังก์ชั่นเขียนใหม่เพื่อทำงานกับสตรีมแบบประปาเขียนใหม่เป็นภาษาอื่นไม่ว่าพิษของคุณจะเป็นยังไงก็ตาม
ฉันต้องการสนับสนุนแถบความคืบหน้าของฉันเอง
มันบรรลุความแม่นยำของตัวละครย่อยโดยใช้Half unicode block
รหัสนี้รวมอยู่ด้วย
แก้ไข: สำหรับรุ่นที่ปรับปรุงตรวจสอบหน้า GitHubของฉัน
ฉันไม่พอใจกับคำตอบของคำถามนี้ สิ่งที่ฉันกำลังมองหาเป็นการส่วนตัวคือแถบความก้าวหน้าที่น่าประหลาดใจตามที่ APT เห็น
ฉันดูที่ซอร์สโค้ด C สำหรับ APT และตัดสินใจที่จะเขียนสิ่งที่เทียบเท่าของฉันสำหรับการทุบตี
แถบความคืบหน้านี้จะยังคงอยู่ที่ด้านล่างของเครื่องอย่างดีและจะไม่รบกวนการส่งออกใด ๆ ที่ส่งไปยังเครื่อง
โปรดทราบว่าขณะนี้แถบได้รับการแก้ไขที่ความกว้าง 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
สิ่งนี้จะสร้างอนันต์ในขณะที่วนรอบที่ดำเนินการในพื้นหลังและสะท้อน "" ทุกวินาที. สิ่งนี้จะแสดง.
ในเปลือก เรียกใช้tar
คำสั่งหรือคำสั่งใด ๆ ที่คุณต้องการ เมื่อเสร็จสิ้นการดำเนินการคำสั่งแล้วฆ่างานที่ผ่านมาทำงานในพื้นหลัง - ซึ่งเป็นที่ที่ไม่มีที่สิ้นสุดในขณะที่ห่วง
กำลังอัพโหลดไฟล์
[##################################################] 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"
}
ที่นี่เราอัปโหลดไฟล์และวาดแถบความคืบหน้าในแต่ละรอบซ้ำ มันไม่สำคัญว่างานใดที่จะถูกดำเนินการตราบเท่าที่เราสามารถรับ 2 ค่า: ค่าสูงสุดและมูลค่าปัจจุบัน
ในตัวอย่างด้านล่างค่าสูงสุดคือและค่าปัจจุบันที่จัดจำหน่ายโดยฟังก์ชั่นบางอย่างและจะเรียกว่า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"
คำสั่ง unix ส่วนใหญ่จะไม่ให้ผลตอบรับโดยตรงกับคุณซึ่งคุณสามารถทำได้ บางตัวจะให้เอาต์พุตกับ stdout หรือ stderr ที่คุณสามารถใช้ได้
สำหรับสิ่งที่คล้ายกับ tar คุณสามารถใช้สวิตช์ -v และไพพ์เอาต์พุตไปยังโปรแกรมที่อัพเดตภาพเคลื่อนไหวขนาดเล็กสำหรับแต่ละบรรทัดที่อ่าน ในขณะที่ tar เขียนรายการของไฟล์โปรแกรมจะไม่สามารถอัปเดตภาพเคลื่อนไหวได้ ในการทำเปอร์เซ็นต์ให้สมบูรณ์คุณจะต้องทราบจำนวนไฟล์และนับจำนวนบรรทัด
cp ไม่ได้ให้ผลลัพธ์แบบนี้เท่าที่ฉันรู้ ในการตรวจสอบความคืบหน้าของ cp คุณจะต้องตรวจสอบไฟล์ต้นทางและไฟล์ปลายทางและดูขนาดปลายทาง คุณสามารถเขียนโปรแกรม c ขนาดเล็กโดยใช้การเรียกระบบstat (2)เพื่อรับขนาดไฟล์ สิ่งนี้จะอ่านขนาดของแหล่งที่มาจากนั้นสำรวจไฟล์ปลายทางและอัปเดตแถบ% สมบูรณ์ตามขนาดของไฟล์ที่เขียนจนถึงปัจจุบัน
โซลูชันของฉันแสดงเปอร์เซ็นต์ของ tarball ที่ไม่ได้บีบอัดและเขียนอยู่ในขณะนี้ ฉันใช้สิ่งนี้เมื่อเขียนอิมเมจระบบไฟล์รูท 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 (ไปป์)
ประการที่สองแถบและ pv สามารถใช้เช่นนี้:
$ bar file1 | wc -l
$ pv file1 | wc -l
หรือแม้กระทั่ง:
$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l
เคล็ดลับที่มีประโยชน์อย่างหนึ่งหากคุณต้องการใช้ประโยชน์จาก bar และ pv ในคำสั่งที่ทำงานกับไฟล์ที่กำหนดในอาร์กิวเมนต์เช่นคัดลอก file1 file2 คือการใช้การทดแทนกระบวนการ :
$ copy <(bar file1) file2
$ copy <(pv file1) file2
การทดแทนโพรเซสเป็นสิ่ง bash magic ที่สร้างชั่วคราวไฟล์ fifo pipe / dev / fd / และเชื่อมต่อ stdout จาก runned โพรเซส (ในวงเล็บ) ผ่านไพพ์นี้และ copy เห็นว่ามันเหมือนกับไฟล์ธรรมดา (ยกเว้นเพียงข้อเดียวเท่านั้นที่สามารถอ่านได้ ไปข้างหน้า)
ปรับปรุง:
คำสั่ง bar นั้นอนุญาตให้ทำการคัดลอกได้เช่นกัน After man bar:
bar --in-file /dev/rmt/1cbn --out-file \
tape-restore.tar --size 2.4g --buffer-size 64k
แต่การทดแทนกระบวนการในความคิดของฉันเป็นวิธีทั่วไปที่จะทำ มันใช้โปรแกรม cp เอง
ฉันชอบที่จะใช้กล่องโต้ตอบกับ--gauge param มีการใช้บ่อยมากในการติดตั้งแพ็คเกจ. deb และการกำหนดค่าพื้นฐานอื่น ๆ ของ distros จำนวนมาก ดังนั้นคุณไม่จำเป็นต้องบูรณาการล้อ ... อีกครั้ง
เพียงแค่ใส่ค่า int จาก 1 ถึง 100 @stdin ตัวอย่างพื้นฐานและไร้สาระหนึ่งตัวอย่าง:
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
จะแสดงความคืบหน้าใน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 นำเสนออินเทอร์เฟซดั้งเดิมสำหรับสคริปต์ทุบตี: 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
ฉันใช้คำตอบจากการสร้างสตริงของอักขระซ้ำในเชลล์สคริปต์สำหรับการทำซ้ำอักขระ ฉันมีสองรุ่นทุบตีที่ค่อนข้างเล็กสำหรับสคริปต์ที่ต้องแสดงแถบความคืบหน้า (ตัวอย่างเช่นการวนซ้ำที่ต้องผ่านหลายไฟล์ แต่ไม่มีประโยชน์สำหรับไฟล์ tar ขนาดใหญ่หรือการคัดลอก) หนึ่งที่เร็วขึ้นประกอบด้วยสองฟังก์ชั่นหนึ่งที่จะเตรียมสายสำหรับการแสดงบาร์:
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
หากคุณต้องการ ProgressBar บน 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;
หนึ่งสามารถใช้ธง / ตัวแปรภายในห่วงขณะที่การตรวจสอบและแสดงค่า / ขอบเขตของความคืบหน้า
เมื่อใช้คำแนะนำที่ระบุไว้ข้างต้นฉันตัดสินใจใช้แถบความคืบหน้าของฉันเอง
#!/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))"
ฉันใช้รุ่น shell บริสุทธิ์สำหรับระบบฝังตัวโดยใช้ประโยชน์จาก:
คุณลักษณะการจัดการสัญญาณ SIGUSR1 / usr / bin / dd
โดยทั่วไปถ้าคุณส่ง 'kill SIGUSR1 $ (pid_of_running_dd_process)' มันจะแสดงผลสรุปของความเร็วในการรับส่งและจำนวนเงินที่โอน
backgrounding dd จากนั้นทำการสืบค้นเป็นประจำเพื่อรับการปรับปรุงและการสร้างเห็บแฮชเช่นไคลเอนต์ ftp โรงเรียนเก่าที่เคยใช้
การใช้ / dev / stdout เป็นปลายทางสำหรับโปรแกรมที่เป็นมิตรที่ไม่ใช่ stdout เช่น scp
ผลลัพธ์สุดท้ายช่วยให้คุณสามารถดำเนินการถ่ายโอนไฟล์และรับการอัปเดตความคืบหน้าซึ่งดูเหมือนว่าเอาต์พุต 'hash' ของ FTP แบบเก่าซึ่งคุณจะได้รับเครื่องหมายแฮชสำหรับ X ไบต์ทุกตัว
นี่คือรหัสคุณภาพการผลิตแทบจะไม่ แต่คุณเข้าใจ ฉันคิดว่ามันน่ารัก
สำหรับสิ่งที่คุ้มค่าจำนวนไบต์ที่แท้จริงอาจไม่สะท้อนอย่างถูกต้องในจำนวนแฮช - คุณอาจมีหนึ่งหรือมากกว่านั้นขึ้นอยู่กับปัญหาการปัดเศษ อย่าใช้สิ่งนี้เป็นส่วนหนึ่งของบททดสอบมันเป็นแค่เรื่องน่ารู้ และใช่ฉันรู้ว่านี่ไม่มีประสิทธิภาพมาก - เป็นเชลล์สคริปต์และฉันไม่ขอโทษ
ตัวอย่างด้วย wget, scp และ tftp ที่ให้ไว้ในตอนท้าย ควรทำงานกับสิ่งที่ปล่อยข้อมูล ตรวจสอบให้แน่ใจว่าใช้ / dev / stdout สำหรับโปรแกรมที่ไม่เป็นมิตรกับ 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
pidof dd
นั้นน่ากลัว
ในกรณีที่คุณต้องแสดงแถบแสดงความคืบหน้าชั่วคราว (โดยรู้ล่วงหน้าถึงเวลาที่แสดง) คุณสามารถใช้ 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
ไปได้ที่จะแสดงแถบความคืบหน้าจากสคริปต์ทุบตีของคุณโดยเรียกใช้คำสั่งต่อไปนี้:
python progressbar.py 10 50
มันจะแสดง50
อักขระขนาดแถบความคืบหน้าและ "กำลังทำงาน" เป็น10
เวลาไม่กี่วินาที
ฉันได้สร้างคำตอบที่กลัวโดย
สิ่งนี้เชื่อมต่อกับฐานข้อมูล Oracle เพื่อดึงความคืบหน้าของการกู้คืน RMAN
#!/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" เป็นขนาดไฟล์เอาต์พุตที่คาดการณ์)