Bash String concatenation and get content - linux

I have a bash loop, I'm trying to read the all variables:
var1="hello1"
var2="hello2"
var3="hello3"
for i in `seq 1 3`;
do
ab=var$i
# Now ab == var1, I want to echo $var1
done
I'm trying to get dynamically var(1)(2)(3) and get out the String of it.
Edit:
The point here is how to concatenation variables like ab=var$i
and using the ab variable (var1 for example) as a variable, I mean to get the var1 value hello1
I didn't mean how to do it to this specific example, and not with arrays.
Hope I have clarified myself.

var1="hello1"
var2="hello2"
var3="hello3"
for i in `seq 1 3`;
do
ab=var$i
echo ${!ab}
done
I'm not sure it is the best solution to your larger problem, but it is the direct solution to your immediate request.

Simpler approach:
var1="hello1"
var2="hello2"
var3="hello3"
eval echo\ $var{1..3}\;
Is expanded to:
echo $var1
echo $var2
echo $var3
Ouput:
hello1
hello2
hello3

Related

Using a for loop input to rename an object within the loop in bash

I am currently trying to rename an input argument by the variable "i" in the following for loop:
cd $1
num=$(echo $#)
echo $num
echo $#
echo "This is the next part where I print stuff"
for i in $(seq 2 $num)
do
echo $i
echo ${!i}
Args_array+=$(printf '${arg_%s[#]}' ${i})
echo $Args_array
arg_${i}=$(ls ${!i})
done
The output is as follows:
4
output_folder /path/to/my.tsv /path/to/my2.tsv /path/to/my3.tsv
2
/path/to/my.tsv
${arg_2[#]}
/var/spool/slurm/d/job6985121/slurm_script: line 23: arg_2=/path/to/my.tsv: No such file or directory
But it will not allow me to rename the $2, $3 arguments with "i" like this. Any help would be appreciated.
I want to pass these arguments into R and have to put them in arg_1, arg_2, etc. format.
Not sure I understand what's being attempted with Args_array so focusing solely on OP's comment: 'have to put them in arg_1, arg_2' and skipping arg_1 since OP's code doesn't appear to care about storing $1 anywhere; then again, is R not capable of processing input parameters from the command line?
One bash idea:
$ cat testme
#!/usr/bin/bash
num=$#
for ((i=2;i<=$num;i++))
do
declare args_$i=${!i}
done
for ((i=2;i<=$num;i++))
do
typeset -p args_$i
done
Taking for a test drive:
$ testme output_folder /path/to/my.tsv /path/to/my2.tsv /path/to/my3.tsv
declare -- args_2="/path/to/my.tsv"
declare -- args_3="/path/to/my2.tsv"
declare -- args_4="/path/to/my3.tsv"

how to assign variable to each value in quotes

Is there a way to assign multiple variables from following string?
edit "admin1" edit "admin2" edit "admin3"
I would like to have
var1=admin1 var2=admin2 var3=admin3
Thanks.
Try this:
read -r trash var1 trash var2 trash var3 <<< $(echo edit "admin1" edit "admin2" edit "admin3")
Would you please try the following:
#!/bin/bash
str='edit "admin1" edit "admin2" edit "admin3"' # input string
pat='[^"]*"([^"]*)"(.*)' # regex to match the string
while [[ $str =~ $pat ]]; do # match the regex
printf -v 'var'$((++n)) "${BASH_REMATCH[1]}"
# assign varN to the matched substring
str="${BASH_REMATCH[2]}" # update "str" by truncating left to right
done <<< "$str"
# see the results
echo "$var1"
echo "$var2"
echo "$var3"
The advantage of the script above is you don't need to know the number of variables in advance.
Explanation of the regex pat:
[^"]* matches a sequence of zero or more any characters other
than double quotes. It works to skip extra strings such as edit.
"([^"]*)" matches a string enclosed with the double quotes.
Bash variable ${BASH_REMATCH[1]} is automatically assigned to the enclosed string, as the pattern is wrapped with parentheses.
(.*) matches the remaining substring. The variable str is re-assigned
to it (being truncated) to be used in the next while loop.
The while loop keeps matching regex pat with str until there is no match.
Then the statement printf -v 'var'$((++n)) "${BASH_REMATCH[1]}" generates a variable
var1, var2, var3, .. assigning them to the strings
enclosed with the double quotes in order.
Here is an illustration how the regex works in the loop:
1st loop:
edit "admin1" edit "admin2" edit "admin3"
<---> <----> <-------------------------->
skipped | |
BASH_REMATCH[1] BASH_REMATCH[2]
var1 := BASH_REMATCH[1]
str := BASH_REMATCH[2]
2nd loop:
edit "admin2" edit "admin3"
<----> <----> <------------>
skipped | |
BASH_REMATCH[1] BASH_REMATCH[2]
var2 := BASH_REMATCH[1]
str := BASH_REMATCH[2]
3rd loop:
edit "admin3"
<----> <---->
skipped |
BASH_REMATCH[1]
var3 := BASH_REMATCH[1]
str := empty
There are a lot of ways to do this, but it really depends on how variable your data is, and how reliably you can parse your inputs. Given your example above, the following here-string and process substitution with the read builtin will work:
read var1 var2 var3 < \
<(sed -r 's/edit ?//g' <<< 'edit "admin1" edit "admin2" edit "admin3"')
echo $var1; echo $var2; echo $var3
This will correctly print:
"admin1"
"admin2"
"admin3"
You can also collect input as indexed or associative arrays, or use indirect variable expansions. However, if your real-world inputs are more complicated, your biggest challenge will be scanning for only the words in quotes, and will likely involve a lot of splitting and looping in one form or another.
This Shellcheck-clean demonstration program uses the built-in regular expression support in Bash:
#! /bin/bash -p
edit_rx='edit[[:space:]]+"([^"]*)"'
all_edits_rx="${edit_rx}[[:space:]]+${edit_rx}[[:space:]]+${edit_rx}"
teststr='edit "admin1" edit "admin2" edit "admin3"'
if [[ $teststr =~ $all_edits_rx ]]; then
var1=${BASH_REMATCH[1]}
var2=${BASH_REMATCH[2]}
var3=${BASH_REMATCH[3]}
else
printf "ERROR: '%s' does not match '%s'\\n" "$all_edits_rx" "$teststr" >&2
exit 1
fi
declare -p var1 var2 var3
An advantage of this approach is that it does a thorough check that the input has the expected format, thus minimizing the risk of Garbage in, garbage out.
If the number of quoted values in the string is not always 3 (and maybe even if it is always 3) it would be better to put the values in an array rather than in numbered variables. This Shellcheck-clean demonstration program shows one way to do it:
#! /bin/bash -p
editlist_rx='^edit[[:space:]]+"([^"]*)"[[:space:]]*(.*)$'
teststr='edit "admin1" edit "admin2" edit "admin3" edit "admin4" edit "admin5"'
tmp=$teststr
vars=()
while [[ $tmp =~ $editlist_rx ]]; do
vars+=( "${BASH_REMATCH[1]}" )
tmp=${BASH_REMATCH[2]}
done
if [[ -n $tmp ]]; then
printf "ERROR: failed match at '%s'\\n" "$tmp" >&2
exit 1
fi
for i in "${!vars[#]}"; do
printf 'vars[%d]=%q\n' "$i" "${vars[i]}"
done
It outputs:
vars[0]=admin1
vars[1]=admin2
vars[2]=admin3
vars[3]=admin4
vars[4]=admin5

reload a variable string inside another string

I have to declare a string composed of different variables at the starting of a loop in order to print it later just with eval $command >> file.txt avoiding retype every time the string $command itself. But my $command string is composed of other variables and I need to be able to update them before printing. Here a brief example:
a=0
command="echo \"$a\""
for i in {1..2}; do
### change variable $a
a="$i"
### print command with the new $a
eval "$command"
done
### (it fails) result:
0
0
I need $a to be reloaded everytime in order to be substituted inside the $command string, thus the loop above will return
### wanted result
1
2
I know there are other strategies to achieve this, but I wonder if there is a specific way to reload a variable inside a string
Thank you very much in advance for any help!
You can use a function instead of a variable assignment
#!/usr/bin/env bash
a=0
command(){ echo "$1" ; }
for i in {1..2}; do
a="$i"
command "$a"
done
Edit: as per #glenn jackman one can use a global variable
command(){ echo "$a"; }
And just call the function without the argument $a
command
When you put a variable inside " its expanded. Use a single quote for command variable assignment.
$a=0
$command="echo \"$a\""
$echo $command
echo "0"
$command='echo \"$a\"'
$echo $command
echo \"$a\"
$
Try
a=0
command='echo $a'
for i in {1..2}; do
### change variable $a
a="$i"
### print command with the new $a
eval "$command"
done

How to pass the values into another code to execute a process in linux

I have code for example script1 as follows:
Hello this is John
Hello this is Michael
Hello this is Andrew
This code is in such a way that it cannot be edited. But if we input 1 it will print 1. Hello this is John, and so on..
I want to write a script in bash that it will automatically take inputs with out manually entering by the user.
I have tried like this
created a file test.txt:
1
2
3
And executed this way: ./script1 < test.txt, but it keeps on iterating like infinite loop.
Can anyone try this. I just want 3 outputs.
My reading of your question is that you are trying to accept input from standard in, but that you have immutable code which expects positional parameters. It would be helpful had you posted the relevant portions of the script that you can't modify.
So, I will assume you have something like this, which accepts positional parameters:
#!/bin/bash
names=("" John Michael Andrew)
say_hello_by_id() {
while [ $# -gt 0 ]; do
echo "Hello this is ${names[$1]}"
shift
done
}
echo "$(say_hello_by_id $#)"
Then, you would need to write a shim which reads values from stdin and passes them as arguments:
while read input; do
./existing.sh "$input"
done
Then do:
./shim.sh < inputs.txt
find_user(){
while read -r values
do
if [ $values == $1 ]; then
echo "hello $1";
fi
done < $2
}
find_user $1 $2
./find_user.sh jhon file.txt

bash shell script concatenate string with period char

I am trying to create following string
Beta-3.8.0
but shell script always omits the . period char no matter what I do.
echo "$readVersion"
if [ -z $readVersion ]
then
echo "readVersion is empty"
exit 1
fi;
IFS=.
set $readVersion
newVersion=$(echo "$2 + 1" | bc)
newBranch="Beta-$1.$newVersion.$3"
echo $newBranch
prints:
3.8.0
Beta-3 9 0
I have also tried
newBranch='Beta-'$1'.'$newVersion'.'$3
or
newBranch="Beta-{$1}.{$newVersion}.{$3}"
although this seems printing the right value echo "$1.$newVersion.$3" why not variable doesnt work ?
I need the variable to use later on in the script...
You can save and restore the IFS once you are done.
oldIFS=$IFS
IFS=.
set $readVersion
newVersion=$(echo "$2 + 1" | bc)
IFS=$oldIFS
newBranch="Beta-$1.$newVersion.$3"
echo "$newBranch"
Or you can quote when printing:
echo "$newBranch"
The former is a better idea IMO since it conveys your intention and would make the rest of the code use the "correct" IFS. The latter just circumvents the problem.

Resources