I am currently using a piece of code like this:
if (( $( eval "echo \${+$foo}" ) )); then
./my-prog
fi
Is there a more elegant or concise way to express this? Originally I tried
if (( ${+${(P)foo}} )); then
./my-prog
fi
but that raised the "bad substitution" error.
There's also the -v operator, which precludes the need for indirect parameter expansion:
if [[ -v $foo ]]; then
./my-prog
fi
This is documented in man zshmisc, in the CONDITIONAL EXPRESSIONS section.
(P) and + can be used in the same parameter expansion, if you use them in the right order:
if (( ${(P)+foo} )); then
./my-prog
fi
Related
I’m wanting to do basically what this function does. It comes from the zsh manual page and other zsh documentation. I’m trying to “vaguely understand” without diving into the fine details what this function is doing and how it works.
In this case, I understand everything more or less except the _wanted line and in particular, is the tag "dynamic-dirs" any arbitrary tag or does it need to match what the higher level driving functions are looking for? I read briefly about tags and it seems like they would need to match up but I can’t find dynamic-dirs anywhere in any code that I’ve grep’ed. Nor have a found any type of list of tags that are used and what they means except the example of “files” and “directories” mentioned in the first few paragraphs of zshcompsys(1).
zsh_directory_name() {
emulate -L zsh
setopt extendedglob
local -a match mbegin mend
if [[ $1 = d ]]; then
# turn the directory into a name
if [[ $2 = (#b)(/home/pws/perforce/)([^/]##)* ]]; then
typeset -ga reply
reply=(p:$match[2] $(( ${#match[1]} + ${#match[2]} )) )
else
return 1
fi
elif [[ $1 = n ]]; then
# turn the name into a directory
[[ $2 != (#b)p:(?*) ]] && return 1
typeset -ga reply
reply=(/home/pws/perforce/$match[1])
elif [[ $1 = c ]]; then
# complete names
local expl
local -a dirs
dirs=(/home/pws/perforce/*(/:t))
dirs=(p:${^dirs})
_wanted dynamic-dirs expl 'dynamic directory' compadd -S\] -a dirs
return
else
return 1
fi
return 0
}
The other question is about the ’n’ section. It is going to return a reply even if the directory doesn’t exist. Am I reading the code right?
I guess this would be nice if I was going to do mkdir ~p:foodog ?
I'm trying to use an associate array to parse options with zparseopts.
I have some working code, shared below, using normal arrays...but it's so awkward and verbose. i want to just ask if -f is present using opts as an associative array, by passing -A as my option to zparseopts, but I can't seem to make it work.
local -a opts
zparseopts -D -a opts f
if [[ ${opts[(ie)-f]} -le ${#opts} ]]; then
echo "force was passed"
else
echo "be kind"
fi
thanks for any help!
When the (i) subscript flag is used with an associative array, the substitution will return the key if a match was found, or an empty value if it was not. So you just need to test for a non-empty string:
local -A opts
zparseopts -D -A opts f
if [[ -n ${opts[(ie)-f]} ]]; then
echo "force was passed"
else
echo "be kind"
fi
To consolidate option parsing, I've used this (slightly cryptic) substitution:
flag=-f; force=${${:-true false}[(w)((${#opts[(i)$flag]}>0?1:2))]}
flag=-q; quiet=${${:-true false}[(w)((${#opts[(i)$flag]}>0?1:2))]}
...
if $force; then
...
if ! $quiet; then
...
I wonder if there is any way to execute script with argument that can be optional.
For example
./script (optional parameter X) path
So typing ./script /Users/name/Documents would execute certain function (I assume that if statement will be crucial) and ./script X Users/mcichecki/Documents will execute another function.
I was trying to do it with optional arguments and it didn't work:
ARG1=${1:-R}
if [ "$1" = "X" ];
then
first_function
else
second_function
fi
If the optional argument were last you could use default values. It doesn't work so well when it is first.
Use $# to check the number of arguments that were passed in.
case $# in
1) ARG1=-R; ARG2=$1;;
2) ARG1=$1; ARG2=$2;;
*) echo "Usage: $0 [parameterX] path" >&2; exit 1;;
esac
I'm wrote a function called test_status that I am trying to incorporate in my tmux status bar. To give some background, my tests will output to a file called .guard_result with either success or failure and the test_status function reads from that file and echoes a 💚 if my tests are passing and a ❤️ if they are failing.
The good news is running test_status works just fine, I'm just having trouble getting it to work with tmux. What am I missing here?
# ~/.oh-my-zsh/custom/aliases.zsh
function test_status {
if [ ! -f "./.guard_result" ]; then
echo "?"
return 1
fi
result="$(cat ./.guard_result)"
if [[ $result == *"success"* ]]
then
echo "💚";
elif [[ $result == *"fail"* ]]
then
echo "❤️";
fi
}
This function works... Here is Tmux configuration (which doesn't show result):
# ~/.tmux.conf
set -g status-right "#(test_status) #[fg=colour245]%d %b %Y #[fg=white]:: #[fg=colour245]%l:%M %p"
I know I must be missing something simple... Thanks for your help!
tmux passes shell commands to /bin/sh not zsh. And even if tmux would use zsh, the function would not be available in that context as ~/.zshrc, which loads oh-my-zsh, is only read for interactive shells.
In order to get the the output of test_status into tmux, I would suggest to put the function into a zsh script and call that.
You can either source ~/.oh-my-zsh/custom/aliases.zsh from within the script and then call test_status:
#!/usr/bin/zsh
# ^ make sure this reflects the path to zsh (`type zsh`)
source ~/.oh-my-zsh/custom/aliases.zsh
test_status
Or you can just put the entire function into the script, so as to not clutter alias.zsh:
#!/usr/bin/zsh
function test_status {
if [ ! -f "./.guard_result" ]; then
echo "?"
return 1
fi
result="$(cat ./.guard_result)"
if [[ $result == *"success"* ]]
then
echo "💚";
elif [[ $result == *"fail"* ]]
then
echo "❤️";
fi
}
Safe the script somewhere (e.g. /path/to/test_status.zsh), make it executable (chmod a+x /path/to/test_status.zsh) and call it by path in the tmux configuration.
I'm trying to write a function that will print out the last 3 elements of $PWD, with a '...' beforehand if there are more than 3 elements.
e.g.
/home/nornagon/src --> ~/src
/home/nornagon/src/foo/bar/baz --> ...foo/bar/baz
This is my code so far, but $foo[-3,-1] doesn't work if the array has too few elements in it.
function custom_pwd() {
d=${PWD/#$HOME/\~}
d=(${(s:/:)d})
echo $d[-4,-1]
}
The zsh already has some nifty prompt processing available with print's -P option. This should do the trick:
custom_pwd() {
d=$(print -P '%3~')
case $d in
('~'*|/*) echo "$d";;
(*) echo "...$d"
esac
}
See man zshmisc, section "EXPANSION OF PROMPT SEQUENCES" for the gory details.
Here's what I came up with, though it's not terribly elegant:
function custom_pwd() {
local d slash
d=${PWD/#$HOME/\~}
case $d in
/*) slash=/ ;;
*) slash= ;;
esac
d=(${(s:/:)d})
d[1]=$slash$d[1]
num=$#d
ellipsis=
if (( num > 3 )); then num=3; ellipsis='…'; fi
echo $ellipsis${(j./.)d[-$num,-1]}
}