For some reason this script will work with all of the 'echo's at the end, but without them $wall is an empty string. This seems like really odd behaviour.
#!/bin/zsh
if [ ! -n "$1" ] ; then
files=(~/pictures/backgrounds/*jpg)
else
while [ $1 ] ; do
files+=(`echo $1/*jpg`)
shift
done
fi
echo $files
N=${#files}
echo $N
((N=RANDOM%N))
echo $N
wall=${files[$N]}
echo $wall
cp $wall ~/wall.jpg
This code will sometimes fail because RANDOM%N can result in zero and zsh array indexes start with 1. You should use RANDOM%N+1 instead.
You can:
setopt ksharrays
to enable zero-based indexing.
From man zshoptions:
Emulate ksh array handling as closely as possible. If this
option is set, array elements are numbered from zero, an array
parameter without subscript refers to the first element instead
of the whole array, and braces are required to delimit a sub‐
script (${path[2]}' rather than just$path[2]').
Related
Well, this must be the most stupid and idiotic behavior I've seen from a programming language.
https://www.bfgroup.xyz/b2/manual/release/index.html says:
Syntactically, a Boost.Jam program consists of two kinds of
elements—keywords (which have a special meaning to Boost.Jam) and
literals. Consider this code:
a = b ;
which assigns the value b to the variable a. Here, = and ; are
keywords, while a and b are literals.
⚠ All syntax elements, even
keywords, must be separated by spaces. For example, omitting the space
character before ; will lead to a syntax error.
If you want to use a literal value that is the same as some keyword,
the value can be quoted:
a = "=" ;
OK, so far so good. So I have this in my Jamroot:
import path : basename ;
actions make_mytest_install
{
echo "make_mytest_install: MY_ROOT_PATH $(MY_ROOT_PATH) PWD $(PWD:E=not_set)" ;
epath = "$(MY_ROOT_PATH)/projects/mytest/bin/gcc-9/release/qt5client" ;
ename = basename ( $(epath) ) ;
echo "epath $(epath) ename $(ename)" ;
}
explicit install-gettext ;
make install-mytest : : #make_mytest_install ;
... and I try this:
bjam install-mytest
...updating 1 target...
Jamfile</home/USER/src/myproject>.make_mytest_install bin/install-mytest
make_mytest_install: MY_ROOT_PATH /home/USER/src/myproject PWD not_set
[ SHELL pstree -s -p 2720269 && echo PID 2720269 PWD /home/USER/src/myproject ]
/bin/sh: 13: epath: not found
/bin/sh: 14: Syntax error: "(" unexpected
.....
...failed Jamfile</home/USER/src/myproject>.make_mytest_install bin/install-mytest...
...failed updating 1 target...
Now - how come that the SIMPLEST assignment to a string, EXACTLY AS in the manual:
epath = "$(MY_ROOT_PATH)/projects/mytest/bin/gcc-9/release/qt5client" ;
... fails, and this variable cannot be found anymore?
What is the logic in this? How the hell is this supposed to work? I would get it if MY_ROOT_PATH was undefined - but the echo before it, shows that it is not? What is this lunacy?
So I cannot believe I'm asking something this trivial, but:
How do you assign a string to a variable in bjam language?
Well, the error gives somewhat of a hint: /bin/sh: -> so apparently inside actions, it is sh that runs - then again, if it was really sh I could have assigned variables, but I can't. So best I could do, was to remove the assignments OUT of actions:
import path : basename ;
epath = "$(MY_ROOT_PATH)/projects/mytest/bin/gcc-9/release/qt5client" ;
# ename = basename ( $(epath) ) ; # nope, causes target install-mytest to not be found :(
# calling a shell for basename works - but adds a damn NEWLINE at end!?!?!?!
ename = [ SHELL "basename $(epath)" ] ;
actions make_mytest_install
{
echo "make_mytest_install: MY_ROOT_PATH $(MY_ROOT_PATH) PWD $(PWD:E=not_set)" ;
echo "epath $(epath) ename $(ename)" ;
}
explicit install-mytest ;
make install-mytest : : #make_mytest_install ;
So, assignment kind of passes, but you still can't get the basename ?!
I still don't understand, who thought this kind of variable management is a good idea ... I don't even understand, how people managed to build stuff with this system
My script test.zsh:
args=$#
argss=($#)
echo ${#:2}
echo ${args:2}
echo ${argss:2}
The output:
$ ./test.zsh foo bar foobar
bar foobar
o bar foobar
o
It looks like args is being initialized as the string of $# instead of as an array. How do I initialize args as an array? ($#) does not seem to work either
You need to put parentheses around $# to make args an array:
args=($#)
In other shells, you should also put quotes around it (args=("$#")) to avoid word splitting, but this is disabled by default in zsh (see the option SH_WORD_SPLIT).
Note that ${#:2} will give you $1 $2 $3 ..., while ${args:2} will give $2 $3 ..., because zsh prepends $0 to $# when you use that form of parameter subscripting for compatibility with other shells.
The preferred zsh way to subscript arrays is ${arr[start,end]}, where end is inclusive and may be negative.
${args[1,-1]} and ${args[#]} will expand to the same thing.
In zsh we can test for the existence of a progragram using this:
(( $+commands[program] )) && program
My question is: How to use commands for testing the existence of two programs instead one?
Found this under Subscript Flags in man 1 zshparam (portions removed, emphasis added):
r if this flag is given, the exp is taken as a pattern
i Like r,
I Like i, but gives the index of the last match, or all possible matching keys in an associative array. On failure substitutes 0, or the empty string for an associative array. This flag is best when testing for values or keys that do not exist.
So to test for both program1 and program2, you can do:
(( $#commands[(I)(program1|program2)] == 2 ))
I guess you could just use the following:
if ((( $+commands[program1] ) && ( $+commands[program2] ))); then
echo 'both command exists'
fi
the same could be done using bash:
if [[ `command -v program1` && `command -v program2`]]; then
echo 'both command exists'
fi
I figured out one way of solving this issue:
alias rm='echo use trash instead!'
(( $+commands[trash] && $+commands[gio] )) && alias trash='gio trash'
I still would like to know if it is possible to use something like:
(( $+commands[program1 program2] ))
I have a simple function like
function clearit() {
REM=$(($LINENO % $LINES))
DIV=$(($LINENO / $LINES))
if [[ $DIV -gt 0 && $REM -lt 3 && $DIV ]]; then
clear
fi
echo $LINENO, $LINES
}
add-zsh-hook preexec clearit
In the above function a static value of $LINE and $LINES is added to the prehook function. I want to get the current value when the prexec is executed. How can I do that ?
For normal shell variables, you will get the current value:
% x=1
% function test_hook() { echo $x; }
% add-zsh-hook preexec test_hook
% true
1
% x=2
1
% true
2
However, $LINENO is a very special variable. From the documentation:
LINENO <S>
The line number of the current line within the current script, sourced file, or shell function being executed, whichever was started most recently. Note that in the case of shell functions the line number refers to the function as it appeared in the original definition, not necessarily as displayed by the functions builtin.
When your hook function is executing, it is by definition the most recently started shell function, script or sourced file. So $LINENO always gives you the current line within your hook function. There is no way to access the $LINENO for the outer scope.
However, even if you could access the outer $LINENO in your hook, it would lead to very strange behaviour in my opinion. Let's say your terminal is 30 lines high ($LINES is 30), it would clear the terminal before executing the 30th, 31st and 32nd command, then nothing for the next 27 commands, then again clearing before the 60th, 61st and 62nd, and so on. I don't think this is remotely what you are trying to achieve...
My input will be as: 04.02.03.00
and my other list will be 04.02.01.00, 04.02.02.00 & 04.02.05.00.
After comparing the input(04.02.03.00) with the given list if the exact match(04.02.03.00) is not in the list then 04.02.02.00 should return as output.
You can use the following as an example with bash
read INPUT
for STRING in 04.02.01.00 04.02.02.00 04.02.05.00
do
if [[ "$INPUT" = $STRING ]]
then
FOUND=1
fi
done
if [[ FOUND -ne 1 ]]
then
echo 04.02.02.00
fi
i agree with Michael just in order that to work i think it would need the "test", so like this. the brackets would help you though protect urself from null variables but thats matter of opinion.
read INPUT
for STRING in 04.02.01.00 04.02.02.00 04.02.05.00
do
if test "$INPUT" = $STRING
then
FOUND=1
fi
done
if test $FOUND -ne 1
then
echo 04.02.02.00
fi