3

I have one of my large file as

foo:43:sdfasd:daasf
bar:51:werrwr:asdfa
qux:34:werdfs:asdfa
foo:234:dfasdf:dasf
qux:345:dsfasd:erwe
...............

here 1st column foo, bar and qux etc. are file names. and 2nd column 43,51, 34 etc. are line numbers. I want to print Nth line(specified by 2nd column) for each file(specified in 1st column). How can I automate above in unix shell. Actually above file is generated while compiling and I want to print warning line in code.

-Thanks,

6 Answers 6

2
while IFS=: read name line rest
do
    head -n $line $name | tail -1
done < input.txt
Sign up to request clarification or add additional context in comments.

1 Comment

If you only want the line in question: head -n $line $name | tail -1
2

while IFS=: read file line message; do
    echo "$file:$line - $message:"
    sed -n "${line}p" "$file"
done <yourfilehere

3 Comments

for efficiency: sed -n "${line}{p;q}"
It is a good practice to save IFS before changing it and restore to it's original state after it is no longer needed. Like: OFS=$IFS; ...; IFS=$OFS
vyegorov: the above only changes it for the duration of the read command. Even inside the body of the loop, it's back to its default value.
0
awk 'NR==4 {print}' yourfilename

or

cat yourfilename | awk 'NR==4 {print}'

The above one will work for 4th line in your file.You can change the number as per your requirement.

2 Comments

to pass the line number: awk -v n=$lineno 'NR==n {print;exit}' file
If the file is getting processed in the middle of another then we should use -v option.But if its an explicit process then we donot require -v option.
0

Just in awk, but probably worse performance than answers by @kev or @MarkReed. However it does process each file just once. Requires GNU awk

gawk -F: '
    BEGIN {OFS=FS}
    { 
        files[$1] = 1
        lines[$1] = lines[$1] " " $2
        msgs[$1, $2] = $3 
    }
    END {
        for (file in files) {
            split(lines[file], l, " ")
            n = asort(l)
            count = 0
            for (i=1; i<=n; i++) {
                while (++count <= l[i])
                    getline line < file
                print file, l[i], msgs[file, l[i]]
                print line
            }
            close(file)
        }
    }
'

Comments

0

This might work for you:

sed 's/^\([^,]*\),\([^,]*\).*/sed -n "\2p" \1/' file |
sort -k4,4 | 
sed ':a;$!N;s/^\(.*\)\(".*\)\n.*"\(.*\)\2/\1;\3\2/;ta;P;D' |
sh

Comments

0
 sed -nr '3{s/^([^:]*):([^:]*):.*$/\1 \2/;p}' namesNnumbers.txt 
 qux 34
  • -n no output by default,
  • -r regular expressions (simplifies using the parens)
  • in line 3 do {...;p} (print in the end)
  • s ubstitute foobarbaz with foo bar

So to work with the values:

fnUln=$(sed -nr '3{s/^([^:]*):([^:]*):.*$/\1 \2/;p}' namesNnumbers.txt)

fn=$(echo ${fnUln/ */})
ln=$(echo ${fnUln/* /})
sed -n "${ln}p" "$fn"

2 Comments

The question is asking how to get line 34 out of file "qux" (and similarly for all the other lines)
@glennjackman: I know. With "qux" and "34" it is trivial: sed -n "${lineno}p" "$filename". You think I should include this in my answer?

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.