{$a..3} does not expand right in shell script - bash

Why the output is {1..3} rather than 123 ?
#!/bin/sh
a=1
for i in {$a..3}
do
echo -n $i
done
If I change {$a..3} to $(echo {$a..3}), it does not work either.

Brace expansion is performed before parameter substitution. But since that isn't a valid brace expansion, it isn't expanded. Use seq instead.

Ignacio's answer is right.
Here are some other solutions!
You can use a c-style for-loop in bash:
for (( i=a; i<=3; i++ ))
Or you can use dangerous eval, but you have to be sure that $a variable can't be anything else but a number, especially if the user is able to change it:
for i in $(echo eval {$a..3})
Or while loop with a variable in pure sh:
i=$a
while [ "$i" -le 3 ]
do
echo -n $i
i=$(( i + 1 ))
done

Related

Bash: write args from back. Can I do this better than N^2?

if [[ $1 == "-r" ]]
then
arr=()
i=0
for var in ${#:2}
do
arr[$i]+=$var
((i++))
done
((i--))
for (( j=$i;$j >= 0;j=$j-1 ))
do
echo ${arr[$j]}
done
fi
this is my script to wrote args from last to first one if I add -r.
Can I do this better?
Because now this is N^2. So I feel like I could do this better but I have no idea how. Any advice?
Just index arguments from the back:
for ((i=1;i<=$#;++i)); do
echo "${#: -$i:1}"
done
See ${parameter:offset:length} expansion in bash manual shell parameter expansion.
You can loop over the arguments from the last to the second. Use indirection to use the number as the name of the variable:
for ((i=$#; i>1; --i)) ; do
printf '%s\n' "${!i}"
done

Shell command to loop over names of output file

I have a C code and I use it to extract file and write in to separate files such as exax0.txt, ..., exax202.txt. To do that I use
for i in $(seq 0 202);
do echo $i | ./f.out exa-NO-hyp.bin exax${i}.txt <<< "${i}"
done
Instead, I would like to have my output files named as exax495.txt, exax535.txt, ..., exax8545.txt. To do so, I tried something like:
for i in $(seq 0 202);
do echo $i | ./f.out exa-NO-hyp.bin exax${(i*40+495)}.txt <<< "${i}"
done
But it says, -bash: exax${i*40}.txt: bad substitution
Can anybody please help me with this?
You can use $((...)) to perform arithmetic.
I.e. a simple use would be:
for i in {1..10}; do touch file$(($i+5)).txt ; done
Or in your case:
for i in $(seq 0 202); do echo $i | ./f.out exa-NO-hyp.bin exax$(($i*40+495)).txt <<< "${i}"; done
See also:
Arithmetic Expansion in the Advanced Bash-Scripting Guide.
Arithmetic Expansion in the Bash Reference Manual

Increment variable value by 1 (shell programming)

I can't seem to be able to increase the variable value by 1. I have looked at tutorialspoint's Unix / Linux Shell Programming tutorial but it only shows how to add together two variables.
I have tried the following methods but they don't work:
i=0
$i=$i+1 # doesn't work: command not found
echo "$i"
$i='expr $i+1' # doesn't work: command not found
echo "$i"
$i++ # doesn't work*, command not found
echo "$i"
How do I increment the value of a variable by 1?
You can use an arithmetic expansion like so:
i=$((i+1))
or declare i as an integer variable and use the += operator for incrementing its value.
declare -i i=0
i+=1
or use the (( construct.
((i++))
The way to use expr:
i=0
i=`expr $i + 1`
The way to use i++ (unless you're running with -e/-o errexit):
((i++)); echo $i;
Tested in gnu bash.
you can use bc as it can also do floats
var=$(echo "1+2"|bc)
These are the methods I know:
ichramm#NOTPARALLEL ~$ i=10; echo $i;
10
ichramm#NOTPARALLEL ~$ ((i+=1)); echo $i;
11
ichramm#NOTPARALLEL ~$ ((i=i+1)); echo $i;
12
ichramm#NOTPARALLEL ~$ i=`expr $i + 1`; echo $i;
13
Note the spaces in the last example, also note that's the only one that uses $i.

How can I get the length of all arguments given to a function in bash?

I'd like to get the length of the string that I get when i use "$*" in my function.
I tried:
echo ${#"$*"}
and
echo ${#"*"}
both gave me a bad substitution error.
I don't think you can do it in a single command. However, this seems to work:
#!/bin/bash
a="$#"
echo "${#a}"
Using a temporary variable is the only one basic way, and you need to unset IFS or set it to empty string to prevent spaces in between. And use $* not $# for it would give you spaces in between:
IFS= eval "__=\"\$*\""
echo "${#__}"
Another way is to loop through all strings:
L=0; for __; do (( L += ${#__} )); done
echo "$L"
You can use one of the following.
expr length "$*"
echo "$*" | awk '{print length}'
$# holds the number of positional parameters passed to the function.
Try it:
#!/bin/bash
t() {
echo "num args=$#"
echo "all $*"
}
t "$#"

Bourne Shell Building and referencing a variable

I have a shell that runs where the preset env variables include:
FOOCOUNT=4
FOO_0=John
FOO_1=Barry
FOO_2=Lenny
FOO_3=Samuel
I can not change the way I get this data.
I want to run a loop that generates up the variable and uses the contents.
echo "Hello $FOO_count"
This syntax is however wrong and that is what I am searching for...
count=$FOOCOUNT
counter=0
while [ $counter -lt $count ]
do
#I am looking for the syntax for: <<myContructedVar= $ + 'FOO_' + $counter>>
counter=`expr $counter + 1`
echo "Greeting #$counter: Hello, ${myContructedVar}."
done
Thanks very much
The key is eval:
count=$FOOCOUNT
counter=0
while [ $counter -lt $count ]
do
myConstructedVar=FOO_$counter
counter=`expr $counter + 1`
echo "Greeting #$counter: Hello, `eval echo \$${myConstructedVar}`."
done
The loop arithmetic is old school - the way I write the code. Modern shells have more arithmetic built in - but the question is tagged Bourne shell.
You'll need an eval and a deferred sigil:
$ foo_0=john
$ count=0
$ name="\$foo_$count"
$ echo $name
$foo_0
$ eval echo "$name"
john
but unless the index is truly important to you, you might use
for i in "$foo_0" "$foo_1" "$foo_2" ... ; do
...
done
and get rid of the badly named pseudo-array. And, if you have an upper bound on the number of the number of foo_x and there are no special characters in the various foos (in particular no character in $IFS which defaults to <space><tab><return>) then you can use the null-argument collapsing feature of the shell and:
$ for i in $foo_0 $foo_1 $foo_2 ; do
> echo '***' $i
> done
*** john
and allow the shell to ignore unset foo_x
It's been a very long time since I've done any Bourne shell but have you tried the eval command?

Resources