Unable to get a system variable work for manuals - zsh

I have the following system variable in .zshrc
manuals='/usr/share/man/man<1-9>'
I run unsuccessfully
zgrep -c compinit $manuals/zsh*
I get
zsh: no matches found: /usr/share/man/man<1-9>/zsh*
The command should be the same as the following command which works
zgrep -c compinit /usr/share/man/man<1-9>/zsh*
How can you run the above command with a system variable in Zsh?

Try:
$> manuals=/usr/share/man/man<0-9>
$> zgrep -c compinit ${~manuals}/zsh*
The '~' tells zsh to perform expansion of the <0-9> when using the variable. The zsh reference card tells you how to do this and more.

From my investigations, it looks like zsh performs <> substitution before $ substitution. That means when you use the $ variant, it first tries <> substitution (nothing there) then $ substitution (which works), and you're left with the string containing the <> characters.
When you don't use $manuals, it first tries <> substitution and it works. It's a matter of order. The final version below shows how to defer expansion so they happen at the same time:
These can be seen here:
> manuals='/usr/share/man/man<1-9>'
> echo $manuals
/usr/share/man/man<1-9>
> echo /usr/share/man/man<1-9>
/usr/share/man/man1 /usr/share/man/man2 /usr/share/man/man3
/usr/share/man/man4 /usr/share/man/man5 /usr/share/man/man6
/usr/share/man/man7 /usr/share/man/man8
> echo $~manuals
/usr/share/man/man1 /usr/share/man/man2 /usr/share/man/man3
/usr/share/man/man4 /usr/share/man/man5 /usr/share/man/man6
/usr/share/man/man7 /usr/share/man/man8

Related

How to set command line args with the space delimited contents of the first command line argument in zsh

I will be getting one command line argument in the script I'm writing which will itself be a space delimited list of the actual command line arguments. I'd like to set the arguments of the current script with these arguments. How might I accomplish that?
I'd like to use set -- but I'm not sure how this would work.
E.g.
Given arguments to my script: -a -b -c
echo $1 # prints "-a -b -c"
You can do this with set -- "${(z)1}". This will split $1 into words, handling quoting the same way the shell itself does:
% cat script.zsh
#!/usr/bin/env zsh
set -- "${(z)1}"
for arg; do
echo "==$arg=="
done
% ./script.zsh "-a -b -c -d'has spaces'"
==-a==
==-b==
==-c==
==-d'has spaces'==
If you also want to remove a level of quotes, use "${(#Q)${(z)1}}" instead.

Defining local variable in Makefile target

How to define local variable in Makefile target?
I would like to avoid repeating filename like:
zsh:
FILENAME := "text.txt"
#echo "Copying ${FILENAME}...";
scp "${FILENAME}" "user#host:/home/user/${FILENAME}"
But I am getting an error:
FILENAME := "text.txt"
/bin/sh: FILENAME: command not found
Same with $(FILENAME)
Trying
zsh:
export FILENAME="text.txt"
#echo "Copying ${FILENAME} to $(EC2)";
Gives me an empty value:
Copying ...
You can't define a make variable inside a recipe. Recipes are run in the shell and must use shell syntax.
If you want to define a make variable, define it outside of a recipe, like this:
FILENAME := text.txt
zsh:
#echo "Copying ${FILENAME}...";
scp "${FILENAME}" "user#host:/home/user/${FILENAME}"
Note, it's virtually never correct to add quotes around a value when assigning it to a make variable. Make doesn't care about quotes (in variable values or expansion) and doesn't treat them specially in any way.
The rules for a target are executed by the shell, so you can set a variable using shell syntax:
zsh:
#FILENAME="text.txt"; \
echo "Copying $${FILENAME}..."; \
scp "$${FILENAME}" "user#host:/home/user/$${FILENAME}"
Notice that:
I'm escaping end-of-line using \ so that everything executes in
the same shell
I'm escaping the $ in shell variables by writing $$ (otherwise
make will attempt to interpret them as make variables).
For this rule, which apparently depends on a file named text.txt,
you could alternatively declare text.txt as an explicit dependency and then write:
zsh: text.txt
#echo "Copying $<..."; \
scp "$<" "user#host:/home/user/$<"

zsh mystery variable expansion

I found this in prezto source code:
# Set the command name, or in the case of sudo or ssh, the next command.
local cmd="${${2[(wr)^(*=*|sudo|ssh|-*)]}:t}"
I've been reading zsh doc a lot but getting nowhere close to what this is about. In experimentation on the shell itself it seems to indicate the [] is some arithmetic thing, which makes sense, but I don't see the part that explains how (w) is supposed to work. It seems to be some magical operator that applies to the math expression...
slu#ubuntu-sluvm ~/.zprezto ❯❯❯ VAR="one two three four"
slu#ubuntu-sluvm ~/.zprezto ❯❯❯ echo ${VAR[2]}
n
slu#ubuntu-sluvm ~/.zprezto ❯❯❯ echo ${VAR[(w)2]}
two
slu#ubuntu-sluvm ~/.zprezto ❯❯❯ echo ${VAR[(w)]}
zsh: bad math expression: empty string
slu#ubuntu-sluvm ~/.zprezto ❯❯❯
It looks pretty messy at first glance, but once you break it into its parts it's quite simple. This is an example of parameter expansion and extended globbing support in ZSH. If you look higher up in the function from which this code sample is, you'll see they set:
emulate -L zsh
setopt EXTENDED_GLOB
So now let's break apart the line you have there:
${
${
2[ # Expand the 2nd argument
(wr) # Match a word
^(*=*|=|sudo|ssh|-*) # Do not match *=*, =, sudo, ssh, or -*
]
}
:t} # If it is a path, return only the filename
You can test this by creating a sample script like this:
#!/bin/zsh
emulate -L zsh
setopt EXTENDED_GLOB
echo "${$1[(wr)^(*=*|sudo|ssh|-*)]}:t}" # changed 2 to 1, otherwise identical
Here's what it outputs:
$ ./test.sh '/bin/zsh'
zsh
$ ./test.sh 'sudo test'
test
$ ./test.sh 'sudo --flag test'
test
$ ./test.sh 'ssh -o=value test'
test
$ ./test.sh 'test'
test
For more information, see the documentation on expansion and csh-style modifiers.

zsh: access last command line argument given to a script

I want to get the last element of $*. The best I've found so far is:
last=`eval "echo \\\$$#"`
But that seems overly opaque.
In zsh, you can either use the P parameter expansion flag or treat # as an array containing the positional parameters:
last=${(P)#}
last=${#[$#]}
A way that works in all Bourne-style shells including zsh is
eval last=\$$#
(You were on the right track, but running echo just to get its output is pointless.)
last=${#[-1]}
should do the trick. More generally,
${#[n]}
will yield the *n*th parameter, while
${#[-n]}
will yield the *n*th to last parameter.
The colon parameter expansion is not in POSIX, but this works in at least zsh, bash, and ksh:
${#:$#}
When there are no arguments, ${#:$#} is treated as $0 in zsh and ksh but as empty in bash:
$ zsh -c 'echo ${#:$#}'
zsh
$ ksh -c 'echo ${#:$#}'
ksh
$ bash -c 'echo ${#:$#}'
$

In UNIX shell scripting: What does $! expand to?

What is the meaning for $! in shell or shell scripting? I am trying to understand a script which has the something like the following.
local#usr> a=1
local#usr> echo $a
1
local#usr> echo $!a
a
It is printing the variable back. Is it all for that? What are the other $x options we have? Few I know are $$, $*, $?. If anyone can point me to a good source, it will be helpful. BTW, This is in Sun OS 5.8, KSH.
The various $… variables are described in Bash manual. According to the manual $! expands to the PID of the last process launched in background. See:
$ echo "Foo"
Foo
$ echo $!
$ true&
[1] 67064
$ echo $!
67064
[1]+ Done true
In ksh it seems to do the same.
From the ksh man page on my system:
${!vname}
Expands to the name of the variable referred to by vname. This
will be vname except when vname is a name reference.
For the shell you are asking, ksh, use the the ksh manual, and read this:
Parameter Substitution
A parameter is an identifier, one or more digits, or any of
the characters *, #, #, ?, -, $, and !.
It is clear that those are the accepted options $*, $#, $#, $?, $-, $$, and $!.
More could be included in the future.
For the parameter $!, from the manual:
"!" The process number of the last background command invoked.
if you start a background process, like sleep 60 &, then there will be a process number for such process, and the parameter $! will print its number.
$ sleep 60 &
[1] 12329
$ echo "$!"
12329
If there is no background process in execution (as when the shell starts), the exansion is empty. It has a null value.
$ ksh -c 'echo $!'
If there is a background process, it will expand to the PID of such process:
$ ksh -c 'sleep 30 & echo $!'
42586
That is why echo $!a expanded to a. It is because there is no PID to report:
$ ksh -c 'echo $!a'
a
Other shells may have a different (usually pretty similar) list of expansions (a parameter with only one $ and one next character).
For example, bash recognize this *##?-$!0_ as "Special parameters". Search the Bash manual for the heading "3.4.2 Special Parameters".
Special Parameters
The shell treats several parameters specially.
It gives the Process id of last backgroundjob or background function
Please go through this link below
http://www.well.ox.ac.uk/~johnb/comp/unix/ksh.html#specvar
! is a reference operator in unix, though it is not called with that name.
It always refers to a mother process. Try typing :! in vi, it takes you to command prompt and you can execute commands as usual until exit command.
! in SQLPLUS also executes the command from the command prompt. try this in sqlplus
SQL> !ls --- this gives the list of files inthe current dir.
$! - obviously gives the process id of the current/latest process.

Resources