Variable substitution in bash printf {} - bash

I am trying to print true 10 times using a var and its not working
count=10
printf 'true\n%.0s' {1..$count}
This works:
printf 'true\n%.0s' {1..10}
I understand that {} are evaluated before vars but I cannot get around it.

That's not a problem with printf, it's a problem with {1..$count}. That expansion can only be done with constants.
for ((i=1; i<=10; i++)); do
printf 'true\n%.0s' "$i"
done
...or, if you really want to expand onto a single command line, collect your arguments into an array first:
arr=()
for ((i=1; i<=10; i++)); do arr+=( "$i" ); done
printf 'true\n%.0s' "${arr[#]}"
To explain why: Brace expansion ({1..10}) happens before parameter expansion ($count). Thus, by the time $count is expanded to 10, no more brace expansion is going to occur.

The other way (using an external process):
printf 'true\n%.0s' $(seq $count)

For the fun of it, here's a slightly bizarre way:
mapfile -n $count a < /dev/urandom; printf 'true\n%.0s' ${!a[#]}

read http://www.cyberciti.biz/faq/unix-linux-iterate-over-a-variable-range-of-numbers-in-bash/
the way to fix this to work is:
printf 'true\n%.0s' $(eval echo "{1..$count}")

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

Bash post increment inside expression

Consider the following script.
i=1
echo $(printf "%02d" $i)
((i++))
echo $(printf "%02d" $i)
The output is:
01
02
I would like to remove the line in the ((i++)) line in the middle, and have something like the following, but it just prints 01 twice.
i=1
echo $(printf "%02d" $((i++)))
echo $(printf "%02d" $i)
How can I get the same output of 01 followed by 02 without a separate statement to do the increment?
I have already looked at this question, and the solution there does not work for this use case.
Update: I am running in a subshell because the real problem is to do variable assignment:
x=$(printf "%02d" $((i++)))
I changed it to echo originally to simplify the example.
It is possible to assign value of a variable without resorting to subshell by using bash builtin printf.
In your case, you want to increment i while executing the 1st statement then use the same variable on the second statement.
Here's how you do it using bash builtin printf.
i=1
printf -v x "%02d" $((i++))
printf -v y "%02d" $i
You will end up with x=01 and y=02.

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.

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

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

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 "$#"

Resources