Created
March 29, 2026 15:31
-
-
Save TaylanTatli/ad3ce56d47a46254a4bc32201685a862 to your computer and use it in GitHub Desktop.
Progressbar script for portainer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| sudo -v || exit 1 | |
| # Portainer PID | |
| PID=$(pgrep portainer) | |
| if [ -z "$PID" ]; then | |
| echo "❌ Error: Portainer is not running..." | |
| exit 1 | |
| fi | |
| echo "-------------------------------------------------------------------" | |
| echo " 🚀 Portainer Download Progress " | |
| echo "-------------------------------------------------------------------" | |
| sudo strace -s 4096 -e write -f -p $PID 2>&1 | \ | |
| grep --line-buffered -oE "[0-9a-f]{12} (Downloading .*MB|Download complete|Extracting|Pull complete)" | \ | |
| python3 -u -c " | |
| import sys, re | |
| try: | |
| def clean_ansi(text): | |
| return re.sub(r'\x1b\[[0-9;]*[mK]', '', text) | |
| layers = {} | |
| BAR_INNER_WIDTH = 40 | |
| def build_line(layer_id, inner_content, status_text): | |
| fill_count = len(inner_content.replace(' ', '')) | |
| scaled_fill = int(fill_count * (BAR_INNER_WIDTH / 50)) | |
| if scaled_fill > BAR_INNER_WIDTH: scaled_fill = BAR_INNER_WIDTH | |
| bar_fill = '■' * scaled_fill | |
| bar_empty = '・' * (BAR_INNER_WIDTH - scaled_fill) | |
| return f'{layer_id} [ {bar_fill}{bar_empty} ] {status_text}' | |
| while True: | |
| line = sys.stdin.readline() | |
| if not line: break | |
| clean_line = clean_ansi(line).strip() | |
| if not clean_line: continue | |
| layer_id = clean_line[:12] | |
| content = clean_line[12:].strip() | |
| display = '' | |
| if 'complete' in content or 'Extracting' in content: | |
| status = 'Done!' if 'complete' in content else 'Extracting...' | |
| display = build_line(layer_id, '=' * 50, status) | |
| elif 'Downloading' in content: | |
| start = content.find('[') | |
| end = content.rfind(']') | |
| if start != -1 and end != -1: | |
| raw_inner = content[start+1:end] | |
| size_match = re.search(r'\]\s+(.*MB)', content) | |
| size_info = size_match.group(1) if size_match else '' | |
| display = build_line(layer_id, raw_inner, f'Downloading ({size_info})') | |
| else: | |
| display = f'{layer_id} {content}' | |
| else: | |
| display = f'{layer_id} {content}' | |
| if layer_id not in layers: | |
| layers[layer_id] = len(layers) | |
| print('') | |
| diff = len(layers) - layers[layer_id] | |
| sys.stdout.write(f'\033[{diff}A\r\033[K{display.ljust(110)}\033[{diff}B') | |
| sys.stdout.flush() | |
| except KeyboardInterrupt: | |
| sys.exit(0) | |
| " |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment