{"id":42141371,"url":"https://github.com/ali5ter/pfb","last_synced_at":"2026-04-01T19:53:04.131Z","repository":{"id":150553570,"uuid":"480417742","full_name":"ali5ter/pfb","owner":"ali5ter","description":"🤩 Pretty feedback for your bash scripts","archived":false,"fork":false,"pushed_at":"2025-12-20T03:43:39.000Z","size":8165,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-21T03:07:55.951Z","etag":null,"topics":["ansi","ansi-escape-sequences","bash","messages","prompt","shell","terminal","tui","utility"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ali5ter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-04-11T14:31:45.000Z","updated_at":"2025-12-20T03:43:42.000Z","dependencies_parsed_at":"2023-07-29T15:31:06.140Z","dependency_job_id":null,"html_url":"https://github.com/ali5ter/pfb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ali5ter/pfb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ali5ter%2Fpfb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ali5ter%2Fpfb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ali5ter%2Fpfb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ali5ter%2Fpfb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ali5ter","download_url":"https://codeload.github.com/ali5ter/pfb/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ali5ter%2Fpfb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28782766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T13:55:28.044Z","status":"ssl_error","status_checked_at":"2026-01-26T13:55:26.068Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansi","ansi-escape-sequences","bash","messages","prompt","shell","terminal","tui","utility"],"created_at":"2026-01-26T17:14:20.918Z","updated_at":"2026-04-01T19:53:04.124Z","avatar_url":"https://github.com/ali5ter.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pfb\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/pfb-hero.png\" width=\"800\" alt=\"pfb – pretty feedback for bash scripts\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003ePretty feedback for Bash scripts.\u003c/strong\u003e\u003cbr\u003e\n  Lightweight • Dependency-free • Pleasant by default\n\u003c/p\u003e\n\n![video of pfb example output](examples/pfb_demo.gif)\n\n## Usage\n\nUse the functions in this script by sourcing it in your scripts, e.g.\n`source [path_to]/pfb.sh`\n\nAn example of pretty feedback provided by pfb can be shown by running the following command.\n\n`source ./pfb.sh \u0026\u0026 pfb test`\n\n### Configuration\n\npfb can be configured using environment variables:\n\n| Variable | Default | Description |\n| :------- | :------ | :---------- |\n| `PFB_SPINNER_STYLE` | `2` | Spinner style (0-17). Run `pfb test` to see all styles |\n| `PFB_SPINNER_LABEL` | `wait` | Spinner/progress prefix label. Set to empty string to suppress the prefix |\n| `PFB_DEFAULT_LOG_DIR` | `$HOME/logs` | Directory where command logs are stored |\n| `PFB_DEFAULT_LOG` | `scripts` | Base name for log files (creates `$PFB_DEFAULT_LOG.log`) |\n| `PFB_NON_INTERACTIVE` | (unset) | Set to `1` to auto-answer prompts with defaults (CI, cron, scripts) |\n| `NO_COLOR` | (unset) | Disable colors (see [no-color.org](https://no-color.org)) |\n| `PFB_NO_COLOR` | `0` | pfb-specific color disable (set to `1` to disable) |\n| `PFB_FORCE_COLOR` | (unset) | Force colors even when not a TTY (must be set before sourcing) |\n\nExample:\n\n```bash\nexport PFB_SPINNER_STYLE=13\nexport PFB_DEFAULT_LOG_DIR=\"/var/log/myscripts\"\nexport NO_COLOR=1  # Disable colors for accessibility\nsource ./pfb.sh\n```\n\n### Log levels\n\n![video of pfb log-levels](examples/log-levels.gif)\n\npfb provides regular log level feedback using the following command.\n\n`pfb [info|warn|error|success] message`\n\n### Headings\n\n![video of pfb headings](examples/headings.gif)\n\npfb provides headings with a leading icon and sub-headings for adding detail under the heading.\n\nA heading is echoed by using the following pfb command.\n\n`pfb heading message [icon]`\n\nSubheadings can be echoed after headings using\n\n`pfb subheading message`\n\nNot really a heading but a formatted subheading indicating a suggestion...\n\n`pfb suggestion message`\n\n### Long running commands\n\n![video of pfb wait spinner](examples/spinner.gif)\n\npfb can provide feedback that a command is being processed using\n\n`pfb spinner start message some_command`\n\nYou can also start a spinner manually and stop it later:\n\n```bash\npfb spinner start message\npfb spinner stop\n```\n\nThe prefix label defaults to `[wait]`. Use `PFB_SPINNER_LABEL` to customise it or set it to\nempty to suppress the prefix entirely:\n\n```bash\nPFB_SPINNER_LABEL=\"deploy\" pfb spinner start \"Deploying to production...\" deploy.sh\n# [deploy] ⣾ Deploying to production...\n\nPFB_SPINNER_LABEL=\"\" pfb spinner start \"Downloading...\" 'curl ...'\n# ⣾ Downloading...\n```\n\nThis is usefully followed up with a pfb success log level message or a pfb answer message.\n\n### Progress bar\n\n![video of pfb progress bar](examples/progress.gif)\n\nFor operations with a known completion percentage, use the determinate progress bar:\n\n`pfb progress \u003ccurrent\u003e \u003ctotal\u003e [message]`\n\nEach call redraws on the same line. Follow the loop with a log-level message to signal\ncompletion:\n\n```bash\nfiles=(*.log)\nfor i in \"${!files[@]}\"; do\n    process \"${files[$i]}\"\n    pfb progress $(( i + 1 )) ${#files[@]} \"Processing files...\"\ndone\npfb success \"All files processed!\"\n```\n\nThe bar adapts to the terminal width and respects `PFB_SPINNER_LABEL` for the prefix\n(including the empty-string no-prefix option). Colors degrade to ASCII `=` characters\nwhen `NO_COLOR` is set:\n\n```bash\n# Color mode (default)\n# [wait] ████████████░░░░░░░░░░░░░░░  42% Downloading...\n\n# No-color mode\n# [wait] [============               ]  42% Downloading...\n```\n\n### Text input\n\n![video of pfb input](examples/input.gif)\n\nCollect text input from the user with an optional default value:\n\n`result=$(pfb input \"prompt message\" [default_value])`\n\nExample:\n\n```bash\nname=$(pfb input \"What's your name?\" \"Anonymous\")\necho \"Hello, $name!\"\n```\n\nThe default value is shown in brackets and used if the user presses enter without typing anything.\n\n### Confirmation prompts\n\n![video of pfb confirm](examples/confirm.gif)\n\nAsk the user a yes/no question and get the result as an exit code:\n\n`pfb confirm \"question\" [yes|no]`\n\nReturns exit code 0 for yes, 1 for no. Use left/right arrow keys, `y`/`n`, or enter to select.\nThe selected option is highlighted and the hint capitalises the current default (`Y/n` or `y/N`).\n\nAn optional second argument sets the default answer (default is `yes`):\n\n```bash\npfb confirm \"Delete all files?\" no    # Defaults to No\npfb confirm \"Continue?\" yes           # Defaults to Yes (explicit)\n```\n\nExample:\n\n```bash\nif pfb confirm \"Delete this file?\"; then\n    rm file.txt\n    pfb success \"File deleted\"\nelse\n    pfb info \"Cancelled\"\nfi\n```\n\n### Selection from a set of options\n\n![video of pfb select](examples/select.gif)\n\npfb provides a way to select from a list of options using the up/down keys using\n\n`pfb select array_of_options`\n\nExample:\n\n```bash\noptions=(\"Option 1\" \"Option 2\" \"Option 3\")\nselected=$(pfb select \"${options[@]}\")\necho \"You selected: ${options[$selected]}\"\n```\n\n### Prompt and answer\n\n![video of pfb prompt-answer](examples/prompt-answer.gif)\n\nFor integrating with external tools like fzf, use the prompt/answer pattern:\n\n`pfb prompt message`\n\nThe pfb answer message can be used to put a formatted answer after the prompt message.\n\n`pfb answer message`\n\nThis pattern saves the cursor position after the prompt and restores it when displaying the answer, keeping everything on\none line. For simple text input, use `pfb input` instead.\n\n## Helper functions and variables\n\nCursor helper functions and color variables are available **immediately after sourcing** `pfb.sh`\n— no prior `pfb` call is required.\n\n\u003e **Note:** Color variables (`INFO_COLOR`, `BOLD`, `RESET`, etc.) are set to ANSI codes only when\n\u003e stdout is a TTY at source time. In CI or piped contexts, set `PFB_FORCE_COLOR=1` **before**\n\u003e sourcing `pfb.sh` to force colors.\n\npfb uses ANSI/VT100 Terminal Control Escape Sequences which you can use yourself:\n\n| Function Name | Use |\n| :------- | ------- |\n| cursor_on | Turn on the cursor |\n| cursor_off | Turn off the cursor |\n| get_cursor_row | Echo the current row number of the cursor |\n| get_cursor_col | Echo the current column number of the cursor |\n| cursor_to row [column] | Move the cursor to a position |\n| cursor_up | Move the cursor to the row above |\n| cursor_down | Move the cursor to the row below |\n| cursor_sol | Move the cursor to the start of the current line |\n| erase_down | Remove all content from the cursor down |\n| erase_up | Remove all content from the cursor up |\n| erase_screen | Remove all content from the screen |\n| erase_eol | Remove all content from the cursor to the end of the line |\n| erase_sol | Remove all content from the cursor to the start of the line |\n| erase_line | Remove all content on the current line |\n| save_pos | Store the current position of the cursor |\n| restore_pos | Restore the position of the cursor to the last saved position |\n| rgb_fg r g b | Set foreground color using RGB values (0-255) |\n| rgb_bg r g b | Set background color using RGB values (0-255) |\n\nExamples of how these area used can be seen in the pfb script.\n\n| Variable Name | Use |\n| :------- | ------- |\n| BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE | Basic 8-color foreground colors |\n| BBLACK BRED BGREEN BYELLOW BBLUE BMAGENTA BCYAN BWHITE | Basic 8-color background colors |\n| INFO_COLOR | Soft blue-cyan (RGB: 100, 180, 220) for info messages |\n| WARN_COLOR | Warm amber (RGB: 255, 180, 80) for warnings |\n| ERROR_COLOR | Clear red (RGB: 240, 90, 90) for errors |\n| SUCCESS_COLOR | Fresh green (RGB: 90, 200, 120) for success |\n| SPINNER_COLOR | Claude orange (RGB: 215, 119, 87) for spinners |\n| PROMPT_COLOR | Bright cyan (RGB: 120, 220, 240) for prompts |\n| BOLD DIM REV RESET | Display attributes |\n\nExamples using these variables:\n\n`printf \"${BYELLOW}${RED}${BOLD}This is bold red text on a yellow background${RESET}\"`\n\n`echo \"${REV}This is reversed text${RESET}\"`\n\n`printf \"${INFO_COLOR}Informational message${RESET}\\n\"`\n\n`printf \"${SUCCESS_COLOR}Success message${RESET}\\n\"`\n\nExamples using RGB color functions:\n\n`printf \"$(rgb_fg 215 119 87)Orange text${RESET}\\n\"`\n\n`printf \"$(rgb_bg 50 150 50)Green background${RESET}\\n\"`\n\n`printf \"$(rgb_fg 255 100 200)$(rgb_bg 50 50 100)Custom colors${RESET}\\n\"`\n\n## Comparison with gum\n\n[gum](https://github.com/charmbracelet/gum) is a more comprehensive TUI toolkit that offers similar functionality with\nadditional components like file browsers, tables, pagers, and advanced text filtering.\n\n**When to use pfb:**\n\n- Zero dependencies - just source a single bash file (~10KB)\n- Maximum portability (works anywhere with bash 4.0+)\n- No external binary installation required\n- Direct function calls (no process spawning overhead)\n- Basic terminal feedback is sufficient for your needs\n\n**When to use gum:**\n\n- Need advanced components (file browser, tables, fuzzy filtering, pagers)\n- Building sophisticated interactive scripts\n- Prefer standalone binaries over sourced libraries\n- Want extensive styling options via CLI flags\n\npfb occupies the lightweight, dependency-free niche — ideal for scripts you distribute or run in constrained\nenvironments where installing external tools adds friction.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fali5ter%2Fpfb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fali5ter%2Fpfb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fali5ter%2Fpfb/lists"}