{"id":22570913,"url":"https://github.com/niedzielski/cb","last_synced_at":"2025-09-18T22:54:39.363Z","repository":{"id":30854966,"uuid":"34412490","full_name":"niedzielski/cb","owner":"niedzielski","description":"📋 Universal command-line clipboard with automatic copy and paste detection. Eg, `cb|sort|cb`. The missing link between GUIs and CLIs!","archived":false,"fork":false,"pushed_at":"2025-09-07T22:33:16.000Z","size":59,"stargazers_count":129,"open_issues_count":2,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-08T00:21:07.762Z","etag":null,"topics":["cli","clipboard","gui"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niedzielski.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.text","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":"2015-04-22T19:55:13.000Z","updated_at":"2025-09-07T22:33:19.000Z","dependencies_parsed_at":"2025-09-18T22:54:39.007Z","dependency_job_id":null,"html_url":"https://github.com/niedzielski/cb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/niedzielski/cb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niedzielski%2Fcb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niedzielski%2Fcb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niedzielski%2Fcb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niedzielski%2Fcb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niedzielski","download_url":"https://codeload.github.com/niedzielski/cb/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niedzielski%2Fcb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275848284,"owners_count":25539541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-18T02:00:09.552Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["cli","clipboard","gui"],"created_at":"2024-12-08T01:14:00.386Z","updated_at":"2025-09-18T22:54:39.354Z","avatar_url":"https://github.com/niedzielski.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📋 cb\n\nUniversal command-line clipboard with automatic copy and paste detection. Eg,\n`cb|sort|cb`.\n\n## Purpose\n\n**cb** is a clipboard for working between graphical and command-line interfaces\n(GUIs and CLIs). The clipboard is a surprisingly convenient integration between\nthe two and doesn't use temporary files. cb automatically performs a copy or a\npaste based on the context.\n\n### Why you don't need cb\n\nIf any of the following are true, you do **not** need cb:\n\n- You use GUIs exclusively.\n- You use CLIs exclusively.\n- You can use the system equivalent copy-and-paste CLIs directly. Eg,\n  [XSel](https://github.com/kfish/xsel) or `pbcopy` / `pbpaste`.\n- You prefer using temporary files when working across GUIs and CLIs.\n\nAll cb provides is a consistent interface across operating systems. Any\nclipboard CLI will do. What's important is how you use the tool.\n\n## Usage\n\nSupply standard input to **copy**:\n\n```console\n$ echo abc|cb\n```\n\nSupply no input to **paste**:\n\n```console\n$ cb\nabc\n```\n\nBoth copy and paste can appear in the same command:\n\n```console\n$ curl \"$(cb)\"|cb\n```\n\nContents on the clipboard can be used bidirectionally with other GUIs like\ngraphical text editors or web browsers using the usual shortcut (control-c/v or\ncommand-c/v).\n\n## Installation\n\n```bash\n# Download the script to ~/bin/cb.\ncurl https://raw.githubusercontent.com/niedzielski/clipboard/main/cb -o ~/bin/cb \u0026\u0026\n\n# Make the script executable.\nchmod +x ~/bin/cb\n```\n\ncb also supports sourcing in Almquist-like shells like `. cb` or `source ./cb`.\n\nThe heart of cb is tiny so edit it however you like and discard the rest!\n\n### Dependencies\n\ncb requires the following dependencies to be installed:\n\n- Linux: xclip on X (eg, `sudo apt install xclip`) and wl-clipboard on Wayland\n  (`sudo apt install wl-clipboard`).\n- macOS: none (`pbcopy` / `pbpaste` are installed by default).\n- Windows: CygUtils (install `putclip` / `getclip` via Cygwin GUI).\n\nIf in doubt, it's simplest to just try executing cb.\n\n### Troubleshooting\n\nIs `~/bin` in the `PATH` environment variable?\n`grep --only-matching ~/bin \u003c\u003c\u003c \"$PATH\"` should report a match. If not, add it\nlike `PATH=\"$PATH\":~/bin`.\n\n## Examples\n\nAll of these examples appear trivial because copy-and-paste is ubiquitous. The\nintent is to demonstrate the understated usefulness of the system clipboard for\nCLI-GUI integration. You can work seamlessly across GUIs and CLIs with it.\n\n- Sort clipboard lines: `cb|sort|cb`. \u003cdetails markdown\u003e\u003csummary\u003eExpand for\n  detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying some lines of text from another program with control or command-C.\n\n  $ printf 'c\\nb\\na'|cb\n\n  $ cb\n  c\n  b\n  a\n\n  $ # Sort the clipboard's contents by line.\n\n  $ cb|sort|cb\n\n  $ # Simulate pasting the text back to another program with control or command-V.\n\n  $ cb\n  a\n  b\n  c\n  ```\n\n  \u003c/details\u003e\n\n- Count the number of bytes, characters, and lines on the clipboard:\n  `cb|wc --bytes --chars --lines`. \u003cdetails markdown\u003e\u003csummary\u003eExpand for\n  detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying text from another program with control or command-C.\n\n  $ echo abc|cb\n\n  $ cb|wc --bytes --chars --lines\n        1       4       4\n  ```\n\n  \u003c/details\u003e\n\n- Replace single quotes with double quotes on the clipboard:\n  `cb|sed s%\\'%\\\"%g|cb`. \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying text from another program with control or command-C.\n\n  $ cb \u003c\u003c\u003c\\'abc\\'\n\n  $ cb|sed s%\\'%\\\"%g|cb\n\n  $ # Simulate pasting the text back to another program with control or command-V.\n\n  $ cb\n  \"abc\"\n  ```\n\n  \u003c/details\u003e\n\n- Diff the clipboard with a file: `diff \u003c(cb) right-hand-side.text`. Works with\n  diff GUIs too: `meld \u003c(cb) right-hand-side.text`.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying some lines of text from another program with control or command-C.\n\n  $ cb \u003c\u003c 'eof'\n  a\n  b\n  eof\n\n  $ # Simulate a previously saved reference.\n\n  $ cat \u003c\u003c 'eof' \u003e right-hand-side.text\n  a\n  b\n  c\n  eof\n\n  $ # Diff the contents of the clipboard with the reference.\n\n  $ diff \u003c(cb) right-hand-side.text\n  2a3\n  \u003e c\n\n  $ # View the same diff in Meld, a graphical diffing program.\n\n  $ meld \u003c(cb) right-hand-side.text\n  ```\n\n  ![Example visual difference of the clipboard (left-hand side) and right-hand-side.text in Meld.](meld.png)\n  \u003c/details\u003e\n\n- Download a file from the URL on the clipboard: `wget \"$(cb)\"`.\n\n- Download a video from the YouTube URL on the clipboard: `youtube-dl \"$(cb)\"`.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying a URL from a browser address bar with control or command-C.\n\n  $ echo 'https://www.youtube.com/watch?v=92c8vW-AzAc'|cb\n\n  $ # Download the address from the clipboard URL.\n\n  $ youtube-dl \"$(cb)\"\n  [youtube] 92c8vW-AzAc: Downloading webpage\n  WARNING: Requested formats are incompatible for merge and will be merged into mkv.\n  [download] Destination: Fritz roars-92c8vW-AzAc.f137.mp4\n  [download] 100% of 5.07MiB in 01:37\n  [download] Destination: Fritz roars-92c8vW-AzAc.f251.webm\n  [download] 100% of 175.94KiB in 00:02\n  [ffmpeg] Merging formats into \"Fritz roars-92c8vW-AzAc.mkv\"\n  Deleting original file Fritz roars-92c8vW-AzAc.f137.mp4 (pass -k to keep)\n  Deleting original file Fritz roars-92c8vW-AzAc.f251.webm (pass -k to keep)\n\n  $ ls Fritz\\ roars-92c8vW-AzAc.mkv\n  'Fritz roars-92c8vW-AzAc.mkv'\n  ```\n\n  \u003c/details\u003e\n\n- Copy from Chromium DevTools `copy($('table:has(\u003e caption)'))` and `cb|html2text`.\n\n- Copy the version of Chromium to the clipboard: `chromium --version|cb`.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Copy the version of Chromium installed into the clipboard.\n\n  $ chromium --version|cb\n\n  $ # Simulate pasting the version into another program with control or command-V.\n\n  $ cb\n  Chromium 97.0.4692.99 built on Debian bookworm/sid, running on Debian bookworm/sid\n  ```\n\n  \u003c/details\u003e\n\n- Copy 10k numbered lines to the clipboard:\n  `for ((i=0; i \u003c 10000; i++)); do echo $i; done|cb`.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Copy numbered lines from 0 to 10000 to the clipboard.\n\n  $ for ((i=0; i \u003c 10000; i++)); do echo $i; done|cb\n\n  $ # Simulate pasting the text into another program with control or command-V.\n\n  $ cb|head\n  0\n  1\n  2\n  3\n  4\n  5\n  6\n  7\n  8\n  9\n  ```\n\n  \u003c/details\u003e\n\n- Replace newlines on the clipboard with commas:\n  `cb|node --input-type=module --eval 'import fs from \"fs/promises\"; const text = await fs.readFile(\"/dev/stdin\", \"utf-8\"); console.log(text.split(\"\\n\").join())'|cb`.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying text delimited by newlines from another program with control or command-C.\n\n  $ echo -ne 'a\\nb\\nc'|cb\n\n  $ cb|node --input-type=module --eval 'import fs from \"fs/promises\"; const text = await fs.readFile(\"/dev/stdin\", \"utf-8\"); console.log(text.split(\"\\n\").join())'|cb\n\n  $ # Simulate pasting the CSV back to another program with control or command-V.\n\n  $ cb\n  a,b,c\n  ```\n\n  \u003c/details\u003e\n\n- Pretty print JSON:\n  `cb|node -pe 'JSON.stringify(JSON.parse(require(\"fs\").readFileSync(0, \"utf-8\")), null, 2)'|cb`.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ # Simulate copying a blob of JSON from another program with control or command-C.\n\n  $ cb \u003c\u003c\u003c'{\"a\":1,\"b\":2,\"c\":3}'\n\n  $ cb|node -pe 'JSON.stringify(JSON.parse(require(\"fs\").readFileSync(0, \"utf-8\")), null, 2)'|cb\n\n  $ # Simulate pasting the JSON back to another program with control or command-V.\n\n  $ cb\n  {\n    \"a\": 1,\n    \"b\": 2,\n    \"c\": 3\n  }\n  ```\n\n  \u003c/details\u003e\n\n- Copy Git patch from one repo to another.\n  \u003cdetails markdown\u003e\u003csummary\u003eExpand for detail…\u003c/summary\u003e\n\n  ```console\n  $ cd clone-a # Enter the repo directory.\n\n  $ git diff|cb # Copy the patch. Run `git add .` first to include untracked files.\n\n  $ cd ../clone-b # Enter the directory of another clone.\n\n  $ cb|git apply # Paste the patch.\n  ```\n\n  \u003c/details\u003e\n\n- Test if the random patch you found online and copied to your clipboard applies\n  to your code: `git apply --check \u003c(cb)`.\n\n- Dump the HEAD revision of a file to the clipboard:\n  `git show HEAD:readme.md|cb`.\n\n- Reverse clipboard line order: `cb|tac|cb`.\n\n- Copy an image to the clipboard: `cb \u003c banana.png`.\n\n- Copy text to the clipboard: `cb \u003c phonebook.csv`.\n\n- Wrap clipboard text at 72 characters:\n  `cb|fold --spaces --width=72|sed 's% \\+$%%'|cb`.\n\n- Find songs, shuffle them, and copy them to the clipboard:\n  `find -iname \\*.flac -printf %f\\\\n|shuf|cb`.\n\n- Copy the absolute path of a filename:\n  `realpath --canonicalize-missing --no-symlinks \"$(cb)\"|cb`.\n\n- Voice the clipboard: `cb|espeak`.\n\n- Truncate the clipboard: `cb|tail|cb`.\n\n- Save the clipboard to a transient file:\n  `t=\"$(mktemp)\" \u0026\u0026 cb \u003e| \"$t\" \u0026\u0026 echo \"$t\"`.\n\n- Edit the clipboard contents in a temporary buffer: `cb|vim -`.\n\n- Compare Gzip and Brotli compressions of the clipboard:\n  `cb|gzip --best|wc --bytes \u0026\u0026 cb|brotli --best|wc --bytes`.\n\n- Copy the most recent photo taken on an Android device to the clipboard:\n  `adb exec-out 'cat \"$(ls -c1 /sdcard/DCIM/Camera/IMG*.jpg|tail -n1)\"'|cb`.\n\n- Convert richtext to plaintext: `cb|cb`.\n\n- Clear the clipboard: `cb \u003c /dev/null`.\n\n## License (Public Domain)\n\nAll code in this repository is public domain and may be used without limitation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniedzielski%2Fcb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniedzielski%2Fcb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniedzielski%2Fcb/lists"}