{"slug": "my-favourite-zsh-bash-shortcuts-functions-and-aliases", "title": "My favourite zsh/bash shortcuts (functions and aliases)", "summary": "A developer shared their favorite zsh/bash shortcuts, including functions and aliases for Git operations, file management, and image conversion. The shortcuts, many AI-generated, aim to save time on frequent tasks like branching, cherry-picking, and creating directories.", "body_md": "My zsh profile is over 1000 lines at this point. A lot of that is functions I asked AI to generate for me, since it's fast, portable, and saves me a ton of typing.\n\nHere's the thing though: the shortcuts that save me the most time aren't the clever ones. They're the dumb ones. Things like `clone`\n\ninstead of `git clone && cd`\n\n, or `dir`\n\ninstead of `mkdir -p && cd`\n\n. Each one only saves a second or two, but I run them so often that it adds up fast.\n\nThese are in no particular order, just the ones I reach for constantly.\n\nA few one-liners I have set up as plain aliases:\n\n```\nalias gcp=\"git cherry-pick\"\nalias git-append=\"git commit --amend --no-edit -a\"\n```\n\n`gcp`\n\nis self-explanatory. `git-append`\n\namends the last commit with your currently staged (and unstaged, thanks to `-a`\n\n) changes without touching the commit message. Great for fixing up a commit you just made before you push.\n\nOne of my most-used functions. Normally you have to remember whether a branch exists before deciding between `git checkout <branch>`\n\nand `git checkout -b <branch>`\n\n. This just does the right thing either way:\n\n```\ngb() {\n  if git rev-parse --verify --quiet \"$1\" >/dev/null; then\n    git checkout \"$1\"\n  else\n    git checkout -b \"$1\"\n  fi\n}\n```\n\nWhen an experiment goes sideways or I just want to throw everything away and start clean, I run `nah`\n\n:\n\n```\nnah() {\n  git reset --hard\n  git clean -df\n  if [ -d \".git/rebase-apply\" ] || [ -d \".git/rebase-merge\" ]; then\n    git rebase --abort\n  fi\n}\n```\n\nThis resets tracked changes, removes untracked files and directories. No confirmation prompt, so use it carefully.\n\nUseful when you need to cherry-pick a batch of commits from one branch onto another in order:\n\n```\nlogs() {\n  if [[ -z \"$1\" || \"$1\" =~ [^0-9] ]]; then\n    echo \"Usage: logs <number_of_commits>\"\n    return 1\n  fi\n  git log -n \"$1\" --reverse --pretty=format:\"gcp %h\"\n}\n```\n\nRun `logs 5`\n\nand you get the last 5 commits printed oldest to newest, each one already formatted as `gcp <hash>`\n\n(using the alias from above). Copy, paste, done.\n\nThis is the one I mentioned that barely saves any time per use, but I run it constantlyn and the time save compounds:\n\n```\ndir() { mkdir -p \"$1\" && cd \"$1\"; }\n```\n\nI got tired of hitting \"No such file or directory\" errors from `mkdir`\n\nwhen the parent folder didn't exist yet, so I just overrode the default behavior globally:\n\n```\nmkdir() {\n  command mkdir -p \"$@\"\n}\n```\n\nNow `mkdir`\n\nalways behaves like `mkdir -p`\n\n.\n\nSame idea as the `mkdir`\n\noverride, but for opening a file in `nano`\n\nwhen the folder it lives in doesn't exist yet:\n\n```\nnano() {\n  if [ $# -eq 0 ]; then\n    command nano\n  else\n    dir=$(dirname \"$1\")\n    if [ ! -d \"$dir\" ]; then\n      mkdir -p \"$dir\"\n    fi\n    command nano \"$@\"\n  fi\n}\n```\n\nInstead of overwriting a file and losing the original, `replace`\n\nmoves it to `~/.Trash`\n\nfirst and then opens a fresh file with the same name in `nano`\n\n:\n\n```\nreplace() {\n  if [[ $# -ne 1 ]]; then\n    echo \"Usage: replace <file>\" >&2\n    return 1\n  fi\n  local file=\"$1\"\n  if [[ ! -f \"$file\" ]]; then\n    echo \"Error: '$file' not found or not a file\" >&2\n    return 1\n  fi\n  mkdir -p ~/.Trash\n  mv \"$file\" ~/.Trash/\n  nano \"$file\"\n}\n```\n\nBut mainly this saves me from runing \"rm && nano \" which I often do when replacing a file from an AI chat or similar. If you need the original back, it's sitting in `~/.Trash`\n\n.\n\niPhone photos default to HEIC, which isn't great for sharing or uploading. These two functions batch-convert them using ImageMagick:\n\n```\nheic2jpg() {\n  if [ $# -eq 0 ]; then\n    echo \"Usage: heic2jpg file1.heic [file2.heic ...]\"\n    return 1\n  fi\n  for f in \"$@\"; do\n    if [ ! -f \"$f\" ]; then echo \"Not found: $f\"; continue; fi\n    magick \"$f\" \"${f%.*}.jpg\"\n  done\n}\n\nheic2png() {\n  if [ $# -eq 0 ]; then\n    echo \"Usage: heic2png file1.heic [file2.heic ...]\"\n    return 1\n  fi\n  for f in \"$@\"; do\n    if [ ! -f \"$f\" ]; then echo \"Not found: $f\"; continue; fi\n    magick \"$f\" \"${f%.*}.png\"\n  done\n}\n```\n\nBoth take any number of files, so `heic2jpg *.heic`\n\nworks fine.\n\nFor getting images web-ready, this wraps `img2webp`\n\nwith sensible defaults and skips anything that isn't actually a file:\n\n```\nimg2webp() {\n  if [[ $# -eq 0 ]]; then\n    echo \"Usage: img2webp <file.png> [file2.png ...] or img2webp *.png\"\n    return 1\n  fi\n\n  for input in \"$@\"; do\n    if [[ ! -f \"$input\" ]]; then\n      echo \"Skipping: '$input' is not a file\"\n      continue\n    fi\n    local output=\"${input%.*}.webp\"\n    echo \"Converting: $input → $output\"\n    command img2webp -lossy -q 80 \"$input\" -o \"$output\"\n  done\n}\n```\n\nRuns at quality 80, lossy, which is a good default for most web use cases. Saves a TON of storage space and bandwidth\n\nSmall ones I use daily without thinking about them:\n\n```\nalias pest=\"./vendor/bin/pest\"\nalias python=\"python3\" # For AI commands expecting it\nalias py=\"python3\" # For me when I'm lazy\n```\n\nThe `pest`\n\nalias saves typing out the full vendor binary path every time I want to run tests. The `python`\n\n/`py`\n\naliases exist because plenty of AI-generated commands assume `python`\n\npoints to Python 3, and half the time I'm too lazy to type the `3`\n\nmyself anyway.\n\nNone of these are groundbreaking on their own. But that's kind of the point: the small, boring shortcuts you run 50 times a day save you more time overall than the clever ones you run once a week. If you're not already keeping a running file of these for yourself, start one. Every time you catch yourself typing the same thing twice, that's a candidate.", "url": "https://wpnews.pro/news/my-favourite-zsh-bash-shortcuts-functions-and-aliases", "canonical_source": "https://dev.to/emmadscodes/my-favourite-zshbash-shortcuts-functions-and-aliases-35n8", "published_at": "2026-07-08 21:43:31+00:00", "updated_at": "2026-07-08 22:11:14.052263+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Git", "ImageMagick", "nano"], "alternates": {"html": "https://wpnews.pro/news/my-favourite-zsh-bash-shortcuts-functions-and-aliases", "markdown": "https://wpnews.pro/news/my-favourite-zsh-bash-shortcuts-functions-and-aliases.md", "text": "https://wpnews.pro/news/my-favourite-zsh-bash-shortcuts-functions-and-aliases.txt", "jsonld": "https://wpnews.pro/news/my-favourite-zsh-bash-shortcuts-functions-and-aliases.jsonld"}}