Home > Software engineering >  How to transfer variables in bash
How to transfer variables in bash

Time:05-30

Good time everyone. I have little experience with bash, but I read everything I found before writing here. I have a text file with lines:

disk1
disk2
disk3

This file is the result of the command:

disk list | awk -F"|" '/backup/ {print $3}' | sed s/' '//g > backupdisks.txt

If we can get rid of it, and output the command and immediately convert the commands into variables, it will be even cooler. The number of lines will change from time to time. I need to take those lines in the bash script and insert them in the

snapshot create --name ${disk}-$now --disk-name ${disk}

I don't understand how to import each line into the variable disk1 , disk2... to then substitute them into the second command as well. I read and tried

while read -r disk
do
    echo "${disk}"
done < backupdisks.txt

and also:

read var2 var3 <data-file

echo "var2 = $var2 var3 = $var3"

and also

file=text.txt
while IFS= read -r line
do
        # echo line is stored in $line
    echo $line
done < "$file"

I guess there is no way I can figure out how this works.

CodePudding user response:

The original question is how to transfer variables.

My answer doesn't actually address the OP question, but provides an alternative approach to what they are trying to do. I will also give the answer to the original question below the alternative approach

ALTERNATIVE APPROACH TO THE PROBLEM


disk list | awk -F"|" '/backup/ { print "now=$(date \047 %Y-%m-%dT%H:%M:%S\047) snapshot create --name " $3 "-$now --disk-name " $3 }' 

This way you will get the output:

now=$(date ' %Y-%m-%dT%H:%M:%S') snapshot create --name disk1-$now --disk-name disk1
now=$(date ' %Y-%m-%dT%H:%M:%S') snapshot create --name disk2-$now --disk-name disk2
now=$(date ' %Y-%m-%dT%H:%M:%S') snapshot create --name disk3-$now --disk-name disk3

This can in turn be piped to bash to actually run it.

So in the end:


disk list | awk -F"|" '/backup/ {print "now=$(date \047 %Y-%m-%dT%H:%M:%S\047) snapshot create --name " $3 "-$now --disk-name " $3 }'  | bash

IMPORTANT NOTE

There is very little error checking in my code. For production code, it's always a good idea to test this type of stuff out very well. For example we are assuming that the disk list command outputs the correct list correctly every time etc.

NOTE about $now

If you want to keep identical timestamp for all disks, then you can put it as an echo in the BEGIN block in awk:


disk list | awk -F"|" 'BEGIN { print "export now=\047$(date  %Y-%m-%dT%H:%M:%S)\047 " } /backup/ {print "snapshot create --name " $3 "-$now --disk-name " $3 }' 

This results in the output:

export now='$(date  %Y-%m-%dT%H:%M:%S)';
snapshot create --name disk1-$now --disk-name disk1
snapshot create --name disk2-$now --disk-name disk2
snapshot create --name disk3-$now --disk-name disk3

You can adjust the value of date or however you get "now" the way you like.

I hope that this gives you starting point.

TRANSFERRING VARIABLES

Let's say that my alternative approach is not valid for the general question of transferring variables then we can approach it like this:

So let's say we have a list that we want to assign to a variable in bash one at a time but we want to preserve and then use that result elsewhere:

cat file | while read line ; do 
     do_something_with $line
done 

but we can go further:

cat file | while read line ; do 
     construct_another_command_with $line
done | command_processor

An example would be to create lines of a shell script like I did in then ALTERNATIVE APPROACH to create a set of lines that bash would understand as a script and then pipe those lines to the bash to execute them.

CodePudding user response:

If it's just one variable per line, xargs is great:

disk list \
    | awk -F"|" '/backup/ {print $3}' \
    | sed s/' '//g \
    | xargs -I '{}' snapshot create --name {}-$now --disk-name {}

-I '{}' tells xargs to replace the string {} with the line it reads from the file. Note that $now is not replaced by xargs and is replaced by regular shell substitution.

For a more generic answer, where lines can contain multiple arguments arguments, then you can use a while read parsing (real example here):

disk list \
    | awk -F"|" '/backup/ {print $3}' \
    | sed s/' '//g \
    | awk '{ print systime() " " $0 }' \
    | while read now disk; do \
        snapshot create --name "${disk}-${now}" --disk-name "${disk}"
    done

That awk '{ print systime() " " $0 }' prepends the current timestamp (to be used as ${now}) to your normal lines (to be used as ${disk}).

So every line would look like this:

1653864092 /backup/disk1
1653864092 /backup/disk2
1653864092 /backup/disk3

Namely, 2 variables per line.

Then, we use read to read the 2 variables and just use them in a command like in a regular shell, very similar to @Ahmed Masud's "TRANSFERRING VARIABLES" answer.

  •  Tags:  
  • bash
  • Related