ZSH subString extraction
You can use the cut command:
echo $1 | cut -c1
echo $1 | cut -c2-
Use $()
to assign these values to variables:
ARG_FIRST=$(echo $1 | cut -c1)
ARG_REST=$(echo $1 | cut -c2-)
echo ARG_FIRST=$ARG_FIRST
echo ARG_REST=$ARG_REST
You can also replace $()
with backticks, but the former is recommended and the latter is somewhat deprecated due to nesting issues.
A1
As others have said, you need to wrap it in curly braces. Also, use a command interpreter (#!
...), mark the file as executable, and call it directly.
#!/bin/zsh
echo $1
echo ${1[1,1]}
A2
The easiest way to extract a substring from a parameter (zsh calls variables parameters) is to use parameter expansion. Using the square brackets tells zsh to treat the scalar (i.e. string) parameter as an array. For a single character, this makes sense. For the rest of the string, you can use the simpler ${parameter:start:length}
notation instead. If you omit the :length
part (as we will here), then it will give you the rest of the scalar.
File test
:
#!/bin/zsh
echo ${1[1]}
echo ${1:1}
Terminal:
$ ./test Hello
H
ello
A3
As others have said, you need (preferably double) square brackets to test. Also, to test if a string is NULL use -z
, and to test if it is not NULL use -n
. You can just put a string in double brackets ([[ ... ]]
), but it is preferable to make your intentions clear with -n
.
if [[ -z "${ARG_FIRST}" ]]; then
...
fi
Also remove the space between #!
and /bin/zsh
.
And if you are checking for equality, use ==
; if you are assigning a value, use =
.
RE:EDIT2:
- Declare all parameters to set the scope. If you do not, you may clobber or use a parameter inherited from the shell, which may cause unexpected behavior. Google's shell style guide is a good resource for stuff like this.
- Use builtins over external commands.
- Avoid backticks. Use
$(...)
instead. - Use single quotes when quoting a literal string. This prevents pattern matching.
- Make use of
elif
orcase
to avoid nestedif
s.case
will be easier to read in your example here, butelif
will probably be better for your actual code.
Using case
:
#!/bin/zsh
typeset ARG_FIRST="${1[1]}"
typeset ARG_REST="${1:1}"
echo $1
echo 'ARG_FIRST='"${ARG_FIRST}"
echo 'ARG_REST='"${ARG_REST}"
case "${ARG_FIRST}" in
('') echo 'nullArgs' ;;
('@') echo '@Args' ;;
(*)
# Recommended formatting example with more than 1 sloc
echo 'regularArgs'
;;
esac
using elif
:
#!/bin/zsh
typeset ARG_FIRST="${1[1]}"
typeset ARG_REST="${1:1}"
echo $1
echo 'ARG_FIRST='"${ARG_FIRST}"
echo 'ARG_REST='"${ARG_REST}"
if [[ -z "${ARG_FIRST}" ]]; then
echo nullArgs
elif [[ '@' == "${ARG_FIRST}" ]]; then
echo @Args
else
echo regularArgs
fi
RE:EDIT3
- Use
"$@"
unless you really know what you are doing. Explanation.
So, I wrote a shell script in a file named test
$ sh test hello
This isn't a zsh
script: you're calling it with sh
, which is (almost certainly) bash
. If you've got the shebang (#!/bin/zsh
), you can make it executable (chmod +x <script>
) and run it: ./script
. Alternatively, you can run it with zsh <script>
.
the result fails. What's wrong with the code?
You can wrap in braces:
echo ${1} # This'll work with or without the braces.
echo ${1[3,5]} # This works in the braces.
echo $1[3,5] # This doesn't work.
Running this: ./test-script hello
gives:
./test-script.zsh hello
hello
llo
./test-script.zsh:5: no matches found: hello[3,5]
Also I don't know how to extract subString from n to the last. Perhaps do I have to use Array split by regex?
Use the [n,last]
notation, but wrap in braces. We can determine how long our variable is with, then use the length:
# Store the length of $1 in LENGTH.
LENGTH=${#1}
echo ${1[2,${LENGTH}]} # Display from `2` to `LENGTH`.
This'll produce ello
(prints from the 2nd to the last character of hello
).
Script to play with:
#!/usr/local/bin/zsh
echo ${1} # Print the input
echo ${1[3,5]} # Print from 3rd->5th characters of input
LENGTH=${#1}
echo ${1[2,${LENGTH}]} # Print from 2nd -> last characters of input.
You can use the cut command:
But that would be using extra baggage - zsh
is quite capable of doing all this on it's own without spawning multiple sub-shells for simplistic operations.