I want to use a set of previous variables created to filter columns of a file called a.ped_snps.temp with awk within bash for loop.

For this, I created bash variables: var_i_1, var_i_2, ... var_i_n_blocks to be the lower bound; and var_f_1, var_f_2, ... var_f_n_blocks to be upper bound.

Note that n_blocks afore mentioned is the number of files that will be created with the columns delimeted by var_i_1 and var_f_1, and so on. I used the follow script:

n_blocks=$(wc -l "a.temp" | awk '{print $1}') # number of blocks to be created, a.temp is the file with the number of blocks

for i in $(seq 1 1 $n_blocks)            # to iterate of first to n_blocks 
    awk -v v_i="$var_i_$i" -v v_f="$var_f_$i" '{     # to declare variables of lower ($var_i_$i) and upper ($var_f_$i) bounds for each iteraction to awk command
    for (i=v_i;i<=v_f;i++) {printf (i==1?"":FS)$i}; print ""     # for statement to print all comlumns between specified in v_i and v_f variables in each iteraction
    }' <a.ped_snps.temp > block_$i.txt       # print one txt file with each block for each iteraction

This code runs and give the files in correct number of iteractions specified in for command, however, only the first column is printed in the output of each file.

When a I used only the awk (as below) with var_i_1 and var_f_1 bash variables (with vaules 2 and 4, respectively, previously stored) the output (block_1.txt) contains only the columns $2, $3 and $4, wich is desired, and so on for the other blocks.

awk -v v_i="$var_i_1" -v v_f="$var_f_1" '{     # declare variables of lower ($var_i_1) and upper ($var_f_1) bounds for first block (set of cloumns)
    for (i=v_i;i<=v_f;i++) {printf (i==1?"":FS)$i}; print ""     # for statement to print only comlumns between specified in v_i and v_f variables for first block
}' <a.ped_snps.temp > block_1.txt       # print one txt file only with a set of columns specified in v_i and v_f variables

So, someone can help me to implement this code in a bash for? In summary, I want to use bash variables previously created in a awk command within bash for.

I hope that I was clear in my explantion.

Thanks in advance.

  • Running a loop around awk is a sign that you should probably rethink what you're doing and rewrite your script in awk alone (or awk plus a much simpler sh wrapper). Looping around awk and wanting to mix in shell code & variables is a good sign that you should rewrite your script in perl. – cas Oct 22 '19 at 5:29

It looks like you are expecting $var_i_$i to expand to the value of $var_i_1, $var_i_2 and so on - unfortunately it doesn't. To illustrate, suppose we set

$ var_i_1=23; var_i_2=45; var_i_3=67


$ for i in $(seq 1 3); do awk -v v_i="$var_i_$i" 'BEGIN{print v_i}'; done

What's happening here is that the shell parses $var_i_$i as $var_i_ concatenated with $i. Since $var_i_ is likely unset/empty, v_i and v_f simply inherit the value of the loop index i.

There are ugly ways of doing the kind of indirection that you want, e.g.

$ for i in $(seq 1 3); do awk -v v_i="$(eval echo \${var_i_$i})" 'BEGIN{print v_i}'; done

however since bash supports arrays, a cleaner solution would be to use arrays for your var_i and var_f values, ex.

$ var_i=(23 45 67)

then (remembering that arrays are zero-indexed)

$ for i in $(seq 0 2); do awk -v v_i="${var_i[i]}" 'BEGIN{print v_i}'; done
| improve this answer | |
  • I solved the problem with you tip, thanks. – andrec Oct 22 '19 at 1:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.