/r/zsh
Zsh is a shell designed for interactive use, although it is also a powerful scripting language.
Please check on the zshwiki.org FAQ and the official FAQ before asking questions.
If your script behaves strange, please check it with shellcheck - it is made for bash scripts but also works with zsh for the most part.
Learning resources can be found in our wiki.
Read zsh FAQ Chapter 02 for more info.
/r/zsh
Been pushing towards the zsh-abbr v6 major version release. I expect only a small minority of users will have to do anything to migrate — the breaking changes are dropping internal things already deprecated in current v5. But just in case: migration guide at https://v6.zsh-abbr.olets.dev/migrating-between-versions.html#upgrading-from-v5-to-v6, and pointers for pinning your major install to 5.x at https://v5.zsh-abbr.olets.dev/installation.html
Hello everyone,
I think my zsh is either broken or that I simply don't understand it quite well :)
When I for example paste this:
sudo systemctl enable --now syncthing@<username>.service
I am met with the following in the shell:
sudo syssudo systemctl--now syncthing@<usernam<>.servic>
But all the text is white except:sudo systemctl
which is green.
It for some reason adds and changes a few things.
And if I press m
I see the suggestion mdadm -AsfR && vgchange -ay
but when I press TAB (which I pressume is "give me the suggestion" I get mMACHTYPMACHTYPE=
Is it supposed to work like this or is something broken?
Sorry for no images, just get errors when I add it in the post.
[Edit: solved https://www.reddit.com/r/zsh/comments/1gg10jp/comment/lum5vh1/ ]
I'm using ${(k)hash[(r)val]}
to look up keys by values in an associative array hash
.
% typeset -A hash=( [a]=b )
% val=b
% echo ${(k)hash[(r)$val]}
a # good
% val=c
% echo ${(k)hash[(r)$val]}
% # good
and ran into this problem:
% val=')'
% echo ${(k)hash[(r)$val]}
% b # bad
I'm guessing that it's related to
% )
zsh: parse error near `)'
I've found that I can guard against the false find by first checking whether the needle is one of the hash's values
% val=')'
% (( ${${(v)hash}[(Ie)$val]} )) && echo ${(k)hash[(r)$val]}
% # good
Anyone have a better way?
Fwiw my real use case is slightly different: my array has heavily-quoted values, ( ['"a"']='"b"' )
, and I'm really doing (( ${${(v)hash}[(Ie)${(qqq)val}]} )) && echo ${(k)hash[(r)${(qqq)val}]}
I have a basic custom function that wraps some NPM commands when in a particular repo:
function unittests() {
local path=$PWD;
local argc="$#"; #arg count
local argv=("$@"); #arg value
local modules; #modules to run
printf -v modules "A/B/%s," "${argv[@]}"
modules=${modules%,}
if [[ $path == "$HOME/code/my-cool-repo" ]]; then
if [[ $argc != 0 ]]; then
npx cross-env ... # run tests for modules, obfuscated for brevity
else
echo "Running tests for my-module...";
npx cross-env ... # run tests for modules, obfuscated for brevity
fi;
else
echo "Not currently in ../my-cool-repo; aborting..."
return 1;
fi;
}
This was working in bash no issue. I migrated to ZSH a few days ago and I get an error when running it: command not found: npx
.
I use NVM and source it (using below command) from my .zshrc
and can verify npm
is loaded with command like npm --version
, npx --version
, etc. It's definitely there.
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
This is my PATH: export PATH="/opt/homebrew/bin:$PATH"
Any clue what the issue could be?
I'm not sure what info would be relevant, so if I need to provide more please let me know.
Thanks!
Hi,
I keep my binaries and scripts in ~/.local/bin, but whenever I add something new to it, Zsh can't find it, and I get a "command not found" error. After a reboot, it works as expected.
I've looked through several articles, but most only cover setting the PATH variable. Maybe I'm missing something in my configuration. Any help would be appreciated. Thanks!
I've bound ctrl arrows
to move between words, but in zsh4humans you could also press ctrl shift arrows
and to move by entire words and alt shift backspace
to remove entire words including words in quotes as if WORDCHARS weren't set. Is this part of some zsh module or was it zsh4humans exclusive feature? I've tried reimplementing it (code) and failed spectacularly
WORDCHARS='*?[]~&;!#$%^(){}<>,|=+'
bindkey '^[[1;5D' backward-word # Ctrl + Left Arrow
bindkey '^[[1;5C' forward-word # Ctrl + Right Arrow
copy -x
- copies last x commands and their outputs in the terminal to the clipboard
I dont know much about shell scripting, I asked chatgpt to do this, but it could only copy the last x inputs (but not the outputs)
thank you. (terminal - default terminal on macOS)
# config management
declare -x -A configs
configs=(
astronvim "$XDG_CONFIG_HOME/astronvim/"
fish "$XDG_CONFIG_HOME/fish/config.fish"
gdb "$XDG_CONFIG_HOME/gdb/gdbinit"
git "$XDG_CONFIG_HOME/git/config"
helix "$XDG_CONFIG_HOME/helix/config.toml"
hx "$XDG_CONFIG_HOME/helix/config.toml"
irssi "$HOME/.irssi"
lazyvim "$XDG_CONFIG_HOME/lazyvim/"
lvim "$XDG_CONFIG_HOME/lvim/config.lua"
nu "$XDG_CONFIG_HOME/nushell"
nvim "$XDG_CONFIG_HOME/nvim"
ohmy "$HOME/.oh-my-zsh"
readline "$HOME/.inputrc"
tridactyl "$XDG_CONFIG_HOME/tridactyl/tridactylrc"
vim "$HOME/.vimrc"
wezterm "$XDG_CONFIG_HOME/wezterm"
xmake "./.xmake/linux/x86_64/xmake.conf"
zsh "$HOME/.zshrc"
ideavim "$HOME/.ideavimrc"
)
for key value in ${(kv)configs}; do
eval "function ${key}config {
if [[ $key == \"zsh\" ]]; then
command \${@:-\$EDITOR} $value && source $value && echo ${configs[zsh]} has been sourced
else
command \${@:-\$EDITOR} $value
fi
}"
done
Now you can modify your ~/.zshrc with zshconfig
and it will source it
You can also pass a editor as argument. Try gdbconfig nano
for example.
I have been relying on this for quite some time and thought I'd share the good word
Hi, i was configuring Oh my zsh, powerlevel10k and all the other cool customizations on the zsh but at some point i broke what i would guess is the end line of my neo vim editor, and now looks like this. Does anyone knows where could i edit that ? Thank you very much.
Hello Community,
I currently use ZSH and Starship as current setup and always wanted to know if you can color certain words in specific colors whenever they appear. As a network consultant I often use SSH connection to networks devices and want for example color the word "down" or "notconnected" in red.
Do you have any idea on how to do that?
MobaXTerm on Windows has something built-in.
So this problem has been driving me crazy for months. zsh just doesn't know how to handle basic keyboard input. You can go in and bind them specifically, but then if you go from terminal A to terminal B, or open tmux or screen, then suddenly it shits the bed and can't handle the keys again. I assumed this was a bug. But based on this thread I just found:
This is actually the intended behavior? Is that correct? You're supposed to figure out how to bind basic keyboard yourself in every different terminal/environment?
Hello,
I'm new to ZSH and appreciate the autocompletion and robbyrussel theme offered by Oh My Zsh (OMZ). However, I've noticed that OMZ can be slower on my system compared to Fish and Bash + Starship.
For context, I'm switching away from Fish due to its cumbersome SSH experience and Bash because of its limited autocompletion feature. Is there a way to use OMZ-like features without the performance overhead?
In summary, I'd like to configure my ZSH to have similar functionality and appearance to OMZ, but I'm not sure where to begin.
So I had a mac for like 4 years and I had set up oh-myzsh in all likelihood. However I got a new mac and I can't seem to find out how to get it back to the way it was.
Previously if I start typing in terminal, then hit tab it would jump to a previous command with that text, and I could keep hitting tab to cycle through previous commands.
e.g. I could type: py then hit tab and it might bring back:
python3 runfile.py
since it was the last command in my history that matches.
Any idea if this was a plugin? I have lost my ,zhrc file.
Thanks
Hi! When using mv **<Tab> A lot of unrelated entries pop up (e.g. .wine-subfolders which in turn contain all! mounted drives). I wanted to get rid of this and added these paths to the ignore-file of fd (which is used by fzf).
This works fine as long as I call fzf directly in the console. However if I use the **-syntax (like above), the output is as before (including these paths). I also tried to export some garbage FZF_DEFAULT_COMMAND, but again this did not change the **-behavior. So somehow the export is not taken into account.
in my .zshrc the relevant lines are export FZF_DEFAULT_COMMAND='fd --type f' plugins=(fzf) source $ZSH/oh-my-zsh.sh
So this should be in the right order, echo $FZF_DEFAULT_COMMAND in a new shell also outputs what is set in the .zshrc.
Any idea why this happens or how I can debug it? Thank you :)
hey folks -
At the start of the default toml config I see this:
"$schema" = 'https://starship.rs/config-schema.json'
The JSON looks like a preconfigured bunch of settings. What is this doing?
I have an alias set to change "docker" to "DOCKER_DEFAULT_PLATFORM=linux/amd64 docker-compose build" from a year ago when I was working a lot with docker.
I dont want that alias to exist anymore. but I cant find it.
I posted my initial help ticket in yesterday, whose comments I reference below. here is the post.
https://www.reddit.com/r/bash/comments/1g2yth1/comment/lrsolob/?context=3
Here is what i've done to find and diagnose the issue:
1a. tried every other possible search technique recommended by chatgpt (desperate, learned a lot)
disabled all potential 3rd party app culprits
booted into safe mode (this stopped the text replacement)
created and used a new user account on my mac (this also stopped the text replacement)
checked in system settings -> keyboard -> text replacement (obviously, not in there.)
tried using keyboard maestro (my normal text replacement strategy) to cancel it with the inverse replacement, which didn't work, because my system seems to be pasting it instead of typing the string, so KM doesn't recognize the trigger string
that tells me that the action lives somewhere in my main users home folder. What I don't understand, is why the search term "docker" or "DOCKER_DEFAULT_PLATFORM=linux/amd64 docker-compose build" return no results. I have no listed aliases other than the main two that boot with macOS (run-help=man which-command=whence)
I am beginning to think this is an issue compounded from macOS software updates since I set it up. how is it possible that there is no executable file or defined alias that returns the culprit, but the text replacement still works? I can hardly get it to work under ideal conditions!
seriously spinning my head at this one. if there are any wizards out there who can help me tackle this issue, I will be forever grateful.
say i have an array with entries that may contain spaces:
arr=(foo bar 'with space' baz)
what is the best way to turn this into:
"foo bar 'with space' baz"
any help is appreciated!
Hello everybody. I am trying to have two things execute when I run `pihole` in my CLI. Obviously I have the actual IP address instead of the brackets.
This is in my .zshrc file:
"""
alias pihole2='ssh -L 8888:localhost:80 pi@[ip address]’
function pihole {
# Uses the alias
pihole2 &
# Open the PiHole admin page
open http://localhost:8889/admin
}
"""
Whenever I type `pihole` in my terminal, it successfully does the ssh connection, but it doesn't open the browser. Am I doing something wrong? Can someone help me please?
I am using MacOS
Hello everyone!
I'm having trouble configuring Powerlevel10k Theme inside my iTerm terminal on my Macbook Pro. I'll start by saying that it's a fairly old Macbook, a mid-2014 model with MacOS Big Sur 11.7.10.
What I would like to get as a configuration is this:
The main problem is that during the configuration of Powerlevel10k I don't see some customization choice that I see are there in the tutorials. I'm pretty sure I've done all the various steps correctly. I installed oh-my-zsh as well as Git and Homebrew but it still doesn't work as I would.
Why do you think I can't configure, for example, the icon before the tilde or the prompt separators?
What I'm getting after the configuration of Powerlevel10k is this:
Thank you for all the explanation!
Caching e.g. eval
calls is nothing new (smartcache is a simple implementation), but I'm wondering if the stuff that typically gets eval
'd in people's configs only change on plugin or system package updates. If so, the cache should get refreshed when they are updated.
But besides that, are there any other reasons the cache should be refreshed and/or certain things that shouldn't be cached? Obviously if what gets eval
d changes on every shell invocation then it wouldn't benefit from caching.
I have an array of plugins:
local -Ua ZPLUGS=(
zsh-users/zsh-autosuggestions
zsh-users/zsh-completions
...
)
plug-clone $ZPLUGS
plug-clone
iterates over the array to ensure the plugins are cloned. They have the naming scheme ~/.cache/zsh/zsh-autosuggestions--zsh-users
(~/.cache/zsh/<plugin>--<plugin_repo>
).
plug-clone
function:
local repo plugdir=$XDG_CACHE_HOME/zsh
local -Ua repodir
# Convert plugins to their expected repo dirs
for repodir in ${${@:-$ZPLUGS}:/(#b)([^\/]#)\/(*)/$plugdir/$match[2]--$match[1]}; do
if [[ ! -d $repodir ]]; then
# Convert back to <plugin>/<plugin_repo> naming scheme for git clone
repo=${repodir:/(#b)(*)\/(*)--(*)}$match[3]/$match[2]
echo "Cloning $repo..."
(
git clone -q --depth 1 --no-single-branch --recursive --shallow-submodules \
https://github.com/$repo $repodir &&
zcomp $repodir/**/*(.DN)
) &
fi
done
wait
Now I want to add branch support to the repos, e.g.:
local -Ua ZPLUGS=(
# Clone the repo, switch to the dev branch
zsh-users/zsh-autosuggestions:dev
)
But I'm stumped on how to get backreferencing to match the optional :dev
after an item in the array for the dev
branch. Or maybe zsh-users/zsh-autosuggestions branch:dev
implementation, whatever makes more sense or is simpler (I don't want quotes to be necessary though, e.g. "zsh-users/zsh-autosuggestions branch:dev" for an item of the array.
Also I'm pretty sure I don't need have backreferencing twice in the code.
Any help is much appreciated, new to Zsh.
So, at some point while working on a project for an OS course, I was required to create a file descriptor with number 99 and assign it to a file, like this: exec 99> file However, zsh returns: zsh: unknown command: 99 And exits with code 127
The weird thing is, it works perfectly with a one-digit fd, say 9. Also, bash has no problem whatsoever with the two-digit fd. I also tried executing the command with zsh -f and it still doesn't work, so it probably isn't caused by my plugins.
ChatGPT insists that zsh imposes a limit on up to 9 file descriptors per process, but I can't find anything similar on the internet.
Is there really such a limit on file descriptors? Can I somehow increase it? Is there any other solution to get problem?
Note: ulimit -n returns 1024 allowed fds by the system
Hi,
I use zsh and oh-my-zsh on my Ubuntu 24.04. The .zshrc
is created by oh-my-zsh init script. I only added these line to enable auto-completion.
autoload -Uz compinit && compinit
zstyle ':completion::complete:*' use-cache 1
I found lots of the packages I want to use, such as eza and distrobox, provided completion support for both bash and zsh. However, I don't get completion for them in zsh. If I jump to a bash shell, I got the completions.
But for what I remember, zsh completion definitions in the site-functions folder should be loaded by default, right? But it feels like only some of them are loaded, e.g. I have completion for rsync and docker commands.
Does anybody know how can I revert last autocompletion (let's say pressing tab when writing ls ~/) to delete the autocompleted subdirectory with backspace?
if required this is my .zshrc: https://github.com/glabka/configs/blob/master/home/.zshrc
Any idea or source is welcomed.
Hello..
I wanted to setup zsh autocomplete for my mac terminal..
So, I have been using WezTerm.
After that I install zsh-autocomplete using homebrew and edited my .zshrc to source the zsh-autocomplete and restarted the terminal.
now.. when I want to do cd to a directory.. it's not showing me the names of directories and all.. I dont know what I am doing wrong.
Below is my .zshrc file. Can anyone please tell me what I am doing wrong?
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
source /opt/homebrew/share/powerlevel10k/powerlevel10k.zsh-theme
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
# history setup
HISTFILE=$HOME/.zhistory
SAVEHIST=1000
HISTSIZE=999
setopt share_history
setopt hist_expire_dups_first
setopt hist_ignore_dups
setopt hist_verify
# completion using arrow keys (based on history)
bindkey '^[[A' history-search-backward
bindkey '^[[B' history-search-forward
# Source other plugins
source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh
source /opt/homebrew/opt/zsh-fast-syntax-highlighting/share/zsh-fast-syntax-highlighting/fast-syntax-highlighting.plugin.zsh
source /opt/homebrew/share/zsh-autocomplete/zsh-autocomplete.plugin.zsh
# ---- Eza (better ls) -----
alias ls="eza --icons=always"
# ---- Zoxide (better cd) ----
eval "$(zoxide init zsh)"
alias cd="z"
# Conda initialization
export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH"
__conda_setup="$('/opt/homebrew/Caskroom/miniforge/base/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/opt/homebrew/Caskroom/miniforge/base/etc/profile.d/conda.sh" ]; then
. "/opt/homebrew/Caskroom/miniforge/base/etc/profile.d/conda.sh"
else
export PATH="/opt/homebrew/Caskroom/miniforge/base/bin:$PATH"
fi
fi
unset __conda_setup
# FZF initialization
source <(fzf --zsh)
I'm on macOS. It's case-insensitive file system, and cd
and PWD
respect that:
% cd /Users/<username> && pwd
/Users/<username>
% cd /users/<username> && pwd
/users/<username>
I'd like to force PWD's capitalization to be what it would be on a case-sensitive file system, while still supporting case-insensitive cd:
% cd /Users/<username> && pwd
/Users/<username>
% cd /users/<username> && pwd
/Users/<username> # <-- changed
I'm imagining a cdpwd hook. So far what I've thought of is a recursively building a path with (pseudocode)
case-sensitive dir name is `ls -F <parent dir name> | grep -i "^<dir name>/$"
and then cd'ing to that.
That's clunky/forky/unoptimized enough to make me say "never mind, I'll stick with the current behavior".
But maybe there's some zsh feature that would give me the case-insensitive version of the PWD, so that the hook function could be
force_pwd_capitalization() {
add-zsh-hook -d chpwd force_pwd_capitalization
cd $CASE_INSENSITIVE_PWD
add-zsh-hook chpwd force_pwd_capitalization
}
or even simply
setopt force_cd_capitalization
?