0

I'd like to know whether below shell script can be simplified further by using a loop

#!/bin/bash

a11=`cat CONTCAR | head -5 | tail -3 | head -1 | awk '{print $1}'`
a12=`cat CONTCAR | head -5 | tail -3 | head -1 | awk '{print $2}'`
a13=`cat CONTCAR | head -5 | tail -3 | head -1 | awk '{print $3}'`
b21=`cat CONTCAR | head -5 | tail -3 | head -2 | awk '{print $1}'`
b22=`cat CONTCAR | head -5 | tail -3 | head -2 | awk '{print $2}'`
b23=`cat CONTCAR | head -5 | tail -3 | head -2 | awk '{print $3}'`
c31=`cat CONTCAR | head -5 | tail -3 | head -3 | awk '{print $1}'`
c32=`cat CONTCAR | head -5 | tail -3 | head -3 | awk '{print $2}'`
c33=`cat CONTCAR | head -5 | tail -3 | head -3 | awk '{print $3}'`
3
  • 4
    edit your question to include some concise, testable sample input (contents of CONTCAR) and expected output and someone will show you how to do it much simpler and without a loop. Also read why-is-using-a-shell-loop-to-process-text-considered-bad-practice Commented May 17, 2016 at 0:31
  • 1
    Wow, Stéphane Chazelas's answer in the aforementioned question by @EdMorton is an amazing must read, perfect for this question. Commented May 17, 2016 at 0:58
  • 2
    cat CONTCAR | head -5 | tail -3 | head -1 | awk '{print $1}' is exactly equivalent to awk 'NR==3{print $1}' CONTCAR Commented May 17, 2016 at 4:07

4 Answers 4

3

Since you haven't provided any sample input and expected output, this is just a guess but it MAY be what you want:

$ cat file
x1 x2 x3 x4
y1 y2 y3 y4
a1 a2 a3 a4
b1 b2 b3 b4
c1 c2 c3 c4
d1 d2 d3 d4
$
$ cat tst.awk
NR>2 && NR<6 {
    for (i=1; i<=3; i++) {
        printf "%c%d%d=%s\n", 97+(NR-3), NR-2, i, $i
    }
}
$
$ declare $(awk -f tst.awk file)
$
$ echo "$a11"
a1
$ echo "$b22"
b2
$ echo "$c33"
c3

but you should consider using arrays instead of all individual variables.

Sign up to request clarification or add additional context in comments.

Comments

2

If you don't want to use arrays loop is not possible since variables are assigned to different names, you can simplify it little bit though

$ read a11 a12 a13 < <(awk 'NR==3{print $1,$2,$3}' CONTCAR)     
$ read b21 b22 b23 < <(awk 'NR==4{print $1,$2,$3}' CONTCAR)        
$ read c31 c32 c33 < <(awk 'NR==5{print $1,$2,$3}' CONTCAR) 

depending on what you are going to use all these nine variables there may be better solutions.

4 Comments

Thank!! It works! What if the variable names are same and only index are different as a11 a12 a13 a21 a22 a23 a31 a32 a33, then more simplification is possible?
they are all different names, different variables. What I meant was bash arrays, but again depend on what you're going to do with those.
OK. rest question: I'm not clear the usage of "< <" . Could you explain that? Thanks in advance
<(..) is file substitution, and < is the usual input redirection. Overall it means take the input for read from the script as if it's coming from a file.
2

Yet another way to do it:

{
    read ignored # ignore first two lines
    read ignored
    read a11 a12 a13 ignored # "ignored" is needed to keep fields 4 on from being included in a13
    read b11 b12 b13 ignored
    read c11 c12 c13 ignored
} <CONTCAR

Comments

0

Assuming that your intent is to only use values 1,2 & 3 from any range where the last digit of the value is whats required in the awk part and the first digit of the value required for the head part - you can try something like this:

for iX in `seq -f %02g 11 33`; do
        if ((${iX:1:1} != 1)) && ((${iX:1:1} != 2)) && ((${iX:1:1} != 3)) ; then
                echo "skipping ${iX}" ; continue ;
        else  # echo "PROCESSING: ${iX}" ;
                TOEXEC="$(cat CONTCAR | head -5 | tail -3 | head -${iX:0:1} | awk '{print ${iX:1:1}}')"
        fi ;
done ;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.