echo value inside a variable? - unix

x=102 y=x
means when i echo $y it gives x
echo $y
x --and not 102
and when i echo $x it give 102
lets say I dnt know what is inside y
and i want the value of x to be echoed with using y someting like this
a=`echo $(echo $y)`
echo $a
Ans 102

You need to tell the shell to evaluate your command twice -- once to turn $y into x, and again to get the value of $x. The most portable way I know to do this is with eval:
$ /bin/sh
$ x=100
$ y=x
$ echo $y
x
$ eval echo \$$y
100
$
(You need to escape the first $ in the eval line because otherwise the first evaluation will replace "$$" with the current pid)
If you're only concerned with bash, KennyTM's method is probably best.

In ksh 93 (I don't know whether this works in ksh 88):
$ x=102; typeset -n y=x
$ echo $x
102
$ echo $y
102
$ echo ${!y}
x
Confusingly, the last two commands do the opposite of what they do in Bash (which doesn't need to flag the variable using typeset).

Related

Using "declare" in Zsh

I am following this thread: https://stackoverflow.com/a/19742842/5057251
for typeset (or declare) in ZSH, not BASH.
#Declare (or typeset) an array of integers
#declare -ai int_array
typeset -ai int_array
int_array=(1 2 3)
echo "${int_array[#]}"
Then
# Attempt to change 1st element to string. (expect to fail)
int_array[1]="Should fail" || echo "error: ${LINENO}"
echo "${int_array[#]}"
Bash finds the error, gracefully reports error and lineno, prints:
1 2 3
But Zsh accepts, prints:
Should fail 2 3
Not sure why different.
There are two problems here:
In bash, and zsh, assigning a string to an integer variable causes that string to be evaluated as an arithmetic expression. Thus, this is not an error:
$ typeset -i foo
$ foo="bar"
If bar was a variable previously set to an arithmetic expression, then bar's expansion would be evaluated as such:
$ bar=10+2
$ typeset -i foo
$ foo="bar"
$ echo "$foo"
12
The error in your assignment, of course, is that there's no way to expand Should fail like that. If it were, say, Should - fail (an arithmetic expression subtracting the value of the two variables Should and fail, for example, it would still work:
$ foo="Should - fail"
$ echo "$foo"
0
The second problem is that nothing in the zsh docs indicate that -i may be set for an entire array, and so the -a in -ai is ignored:
bash-5.0$ typeset -ai foo
bash-5.0$ declare -p foo
declare -ai foo=([0]="0") # the previous value was retained in the array
vs zsh:
% typeset -ai foo
% foo[1]=10
% foo[2]=20
% declare -p foo
typeset -i foo=20 # treated as a normal variable, not array
What you're seeing is essentially int_array being redeclared as an array (without any qualifiers) when you do int_array=(1 2 3):
% foo=(1 2 3)
% declare -p foo
typeset -a foo=( 1 2 3 )
Using zsh typeset can produce a few possible outcomes:
- no errors, works (yeah!).
- errors, script fails (fix!).
- no errors, but unexpected behavior. (scratch head)
As an example of last category, this produces no errors, but the typeset -p reveals -i is ignored.
{
unset int_array
typeset -ia int_array
int_array=(1 2 3)
echo $? "-Point A"
typeset -p int_array
} always {
echo $? "-Point B"
typeset -p int_array
(( TRY_BLOCK_ERROR=0 ))
}
echo $? "-Point C"
echo "survived"
produces
0 -Point A
typeset -a int_array=( 1 2 3 )
0 -Point B
typeset -a int_array=( 1 2 3 )
0 -Point C
survived
The first line unsets int_array. The typeset command declares
int_array to be both an array and int, which is not what zsh allows. The next
line assigns int_array to a value. There is no error as the $? tells us,
but close examination of final typeset -p int_array reveals what actually
happened.
With a small change, we can produce errors and use the always block and
typeset -p to find more details.
{
unset int_array
typeset -ia int_array=(1 2 3) # error
echo $? "-Point A"
typeset -p int_array
} always {
echo $? "-Point B"
typeset -p int_array
(( TRY_BLOCK_ERROR=0 ))
}
echo $? "-Point C"
echo "survived"
040_declare_version2.sh:typeset:135: int_array: inconsistent type for assignment
1 -Point B
040_declare_version2.sh:typeset:140: no such variable: int_array
1 -Point C
survived
The only difference is int_array was given a value in the faulty typeset -ia statement.
This produces errors, and the script jumps to the always block.
The (( TRY_BLOCK_ERROR=0)) allows the script to continue
and not terminate, but the error is still reported at "Point C".
To check shell version:
$SHELL --version
zsh 5.4.2 (x86_64-ubuntu-linux-gnu)

Unix Script to remove last seven characters from a variable

Need to remove the last seven characters from a variable.
For example if my variable string is
COLUMN_NAME||','||
then it should output COLUMN_NAME
I have tried the below but last pipe symbol only getting removed
var=$(lastline%|)
var=$(lastline%|*)
Result : COLUMN_NAME||','|
To remove the last 7 characters:
$ var="COLUMN_NAME||','||"
$ echo "${var%???????}"
COLUMN_NAME
To remove everything after the first pipe:
$ echo "${var%%|*}"
COLUMN_NAME
See https://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion
and https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching
The old school way
echo "COLUMN_NAME||','||" | rev|cut -c 8-|rev
So you are just reversing the string, deleting first 7 characters and again reversing the string.
Use the $variable with echo to do the same.
You can also use awk like below which would be faster.
awk '{print substr($0, 1, length($0)-7)}'
Example:
$ export variable1="COLUMN_NAME||','||"
$ echo $variable1|rev|cut -c 8-|rev
COLUMN_NAME
$ echo $variable1|awk '{print substr($0, 1, length($0)-7)}'
COLUMN_NAME
You need to use two % to strip the longest match:
$ r="COLUMN_NAME||','||"
$ echo ${r%%|*}
COLUMN_NAME
As BashFAQ says in Removing part of a string:
% means "remove the shortest possible match from the end of the
variable's contents".
%% means "remove the longest possible match from the end of the
variable's contents".
You could find the length of your string/s and index from that point:
str1="1234567890foobar";
strlen=${#str1};
str2=${str1:0:$strlen-7};
echo $str2;

How to turn strings on the command line into individual positional parameters

My main question is how to split strings on the command line into parameters using a terminal command in Linux?
For example
on the command line:
./my program hello world "10 20 30"
The parameters are set as:
$1 = hello
$2 = world
$3 = 10 20 30
But I want:
$1 = hello
$2 = world
$3 = 10
$4 = 20
$5 = 30
How can I do it correctly?
You can reset the positional parameters $# by using the set builtin. If you do not double-quote $#, the shell will word-split it producing the behavior you desire:
$ cat my_program.sh
#! /bin/sh
i=1
for PARAM; do
echo "$i = $PARAM";
i=$(( $i + 1 ));
done
set -- $#
echo "Reset \$# with word-split params"
i=1
for PARAM; do
echo "$i = $PARAM";
i=$(( $i + 1 ));
done
$ sh ./my_program.sh foo bar "baz buz"
1 = foo
2 = bar
3 = baz buz
Reset $# with word-split params
1 = foo
2 = bar
3 = baz
4 = buz
As an aside, I find it mildly surprising that you want to do this. Many shell programmers are frustrated by the shell's easy, accidental word-splitting — they get "John", "Smith" when they wanted to preserve "John Smith" — but it seems to be your requirement here.
Use xargs:
echo "10 20 30" | xargs ./my_program hello world
xargs is a command on Unix and most Unix-like operating systems used
to build and execute command lines from standard input. Commands such as
grep and awk can accept the standard input as a parameter, or argument
by using a pipe. However, others such as cp and echo disregard the
standard input stream and rely solely on the arguments found after the
command. Additionally, under the Linux kernel before version 2.6.23,
and under many other Unix-like systems, arbitrarily long lists of
parameters cannot be passed to a command,[1] so xargs breaks the list
of arguments into sublists small enough to be acceptable.
(source)

How to split each element of an array in zsh?

If I have an array:
x=( a:1 b:2 c:3 )
How can I split each element of the array on the colon? I'm trying to do this in order to form an associative array.
I've tried several variations on this, but none seem to work:
print -l ${(s,:,)x}
Is this possible? If so, what am I missing?
Ok - further thinking got me to this solution, that might probably be applicable to the problem behind the question asked:
Loop through the array x!
> x=(a:1 b:2 c:3)
> typeset -A z
> for i in $x; do z+=(${(s,:,)i}); done
> echo $z
1 2 3
> echo ${z[a]}
1
I hope that's more helpful than the first answer(s) :-)
Since x is an array, you shouldn't forget the [#], i.e. print ${(s,:,)x[#]}; thus your code becomes print -l ${(s,:,)x[#]}; but the solution is still another step:
> typeset -A z
> x="a:1 b:2 c:3"
> z=($(echo ${(s,:,)x}))
> echo $z[a]
1
The assignement to the associative array is done with the output of the echo statement.
To clarify further and include your original example x:
> typeset -A z
> x=(a:1 b:2 c:3)
> z=($(echo ${(s,:,)x[#]}))
> echo ${z[a]}
1
> echo ${z[b]}
2
(edit: switched thoughts midwriting :-D, should make more sense now)
(edit 2: striked brainf*rt - similarities between zsh and bash aren't as broad as I assumed)
typeset -A x will make x an associative array
$ typeset -A x
$ x=( a 1 b 2 c 3 )
$ echo $x[a]
1
$ echo $x[c]
3
$ x[d]=5
$ echo $x[d]
5
But i don't know how to split on the colon if you need to start from the string "a:1 b:2 c:3".

how can i source last N lines of a shell script

for example
a=1;b=2;c=3;d=4;e=5
the file is 1.sh
cat 1.sh
echo $a
echo $b
echo $c
echo $d
echo $e
i use the command
source 1.sh
i get
1
2
3
4
5
how can i source the last 3 line of 1.sh?
tail -n 3 1.sh|xargs -0 sh -c
can not work because the variable can not pass to sh
tail -n 3 1.sh > tmp.sh ; source ./tmp.sh ; rm tmp.sh
If necessary, choose or generate a name that's unlikely to collide with anything else, like /tmp/tmp$$.sh.

Resources