Home > database >  assign 2 variables in 1 command
assign 2 variables in 1 command

Time:08-08

I have bash script that prints me table: timestamp, value1, value2, and ratio between value1/value2. For example:

2022-08-07 21:00  2784000/8750=318
2022-08-07 20:00  2792000/8760=318
2022-08-07 19:00  2790000/8760=318
2022-08-07 18:00  2776000/8750=317
2022-08-07 17:00  2804000/8570=327
2022-08-07 16:00  2799000/8580=326
2022-08-07 15:00  2783000/8590=323
2022-08-07 14:00  2729000/8580=318
2022-08-07 13:00  2638000/8530=309
2022-08-07 12:00  2637000/8490=310
2022-08-07 11:00  2610000/8450=308
2022-08-07 10:00  2595000/8470=306
2022-08-07 09:00  2616000/8490=308
2022-08-07 08:00  2604000/8470=307
2022-08-07 07:00  2619000/8450=309
2022-08-07 06:00  2626000/8530=307
2022-08-07 05:00  2627000/8530=307
2022-08-07 04:00  2634000/8530=308
2022-08-07 03:00  2626000/8470=310
2022-08-07 02:00  2625000/8530=307
2022-08-07 01:00  2676000/8540=313
2022-08-07 00:00  2654000/8590=308
2022-08-06 23:00  2673000/8610=310
2022-08-06 22:00  2641000/8570=308
2022-08-06 21:00  2655000/8610=308
2022-08-06 20:00  2665000/8670=307
2022-08-06 19:00  2672000/8670=308
2022-08-06 18:00  2626000/8680=302
2022-08-06 17:00  2581000/8690=297
2022-08-06 16:00  2581000/8720=295
2022-08-06 15:00  2560000/8720=293

Now after sorting it basing on value on right side of '=' ./script.sh | cut -f2,2 -d= | sort -n . Now I want to assign max and min. Ofc its easy to assign max as output of last line, and min as 1st line but assigning 2 variables leads to 2 executions of script.sh. Is there any smarter way to fetch max and min without printing output 2 times?

CodePudding user response:

Use any command that prints only the first and last line (e.g. sed -n '1p;$p') then read both lines into an array using mapfile, or put both lines into a single one with a separator that does not appear in the input, and read two variables.

IFS=' ' read -r min max < <(./script.sh |
  cut -f2,2 -d= | sort | sed -n '1p;$p' | tr '\n' ' ')

That would be one way to do it. But as Ted Lyngmo commented: There is most likely a more efficient way depending on the content of script.sh.
Even now, we could do without the sort (probably the costliest part of your pipeline) when using a custom script that retrieves the min and max in a single unsorted pass, e.g. something like ...

IFS=' ' read -r min max < <(./script.sh |
  awk -F '=' -v min=999999 -v max=-999999 '
  $2<min {min=$2} $2>max{max=$2} END {print min, max}')

CodePudding user response:

Instead of adding another subprocess call we can replace the current cut/sort with a single awk call to extract min/max:

./script.sh | awk -F= '
FNR==1 { min=max=$2 }
       { min=($2<min ? $2 : min)
         max=($2>max ? $2 : max)
       } 
END    { print min,max }'

This generates:

293 327

Feeding to read to populate the bash variables:

read -r min max < <(./script.sh | awk -F= '
FNR==1 { min=max=$2 }
       { min=($2<min ? $2 : min)
         max=($2>max ? $2 : max)
       }
END    { print min,max }')

### or collapsing into a single line:

read -r min max < <(./script.sh | awk -F= 'FNR==1{min=max=$2}{min=($2<min?$2:min);max=($2>max?$2:max)}END{print min,max}')

Both of these generate:

$ typeset -p min max
declare -- min="293"
declare -- max="327"

NOTE: if the purpose of script.sh is to generate some output to be parsed for min/max then a better approach may be to modify script.sh to just generate the min/max; on the other hand if script.sh output is to be used for multiple purposes then consider redirecting stdout to a file and then parsing said file as needed

  • Related