0

How to search for a string from/after certain line in text file using bash script?

E.g. I want to search for first occurrence of "version:" string but not at start of file but at line no. say 35 which contains text *-disk:0 so that I would get product name of disk-0 only and nothing else. My current approach is as follows where line_no was line no. of the line where disk:0 is present. But sometimes there is vendor name also present in-between the disk:0 and version. At that time, this logic fails.

ver_line_no=$(echo $(( line_no + 6 ))) ver_line_text=`sed -n ${ver_line_no}p $1` check_if_present=`echo $fver_line_text | grep "version:"` 

Background: I am trying to parse output of lshw commmand.

*-disk:0 description: ATA Disk product: SAMSUNG physical id: 0 bus info: scsi@z:y:z:0 logical name: /dev/sda version: abc serial: pqr size: 2048GiB capabilities: axy, pqr configuration: pqr, abc, ghj *-disk:1 description: ATA Disk product: TOSHIBA physical id: 0 bus info: scsi@p:q:z:0 logical name: /dev/sdb version: nmh serial: pqasd size: 2048GiB capabilities: axy, pqr configuration: pqr, abc, ghj 

This is the sample information. I want to print information in tabular format using bash script.

5 Answers 5

1

You should be able to cut out the block you want with sed, then use grep:

sudo lshw | sed -n '/\*-disk:0/,/\s*\*/p' | grep 'version:' 

The sed command does not print any lines (-n), then finds the block between *-disk:0 and the next * and prints only that (p).

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

Comments

1

sed solution:

If you want to search for first occurrence after given line number (e.g. 10).

l=10 lshw | sed -n "${l},$ {/version/{p;q}}" 

If you want to search for first occurrence after given line content (e.g. *-disk:0)

lshw | sed -n '/*-disk:0/,${/version/{p;q}}' 

Comments

0

You may use this awk that searches for *-disk:0 in a file to toggle a flag to true:

awk -F: '$1 ~ /\*-disk$/{p = ($2 == 0)} p && /^[[:blank:]]*version:/' file 

 version: abc 

Comments

0

You need to print all lines up the end. The $ represents the end in sed.

sed -p '6,$p' 

Will print lines from 6th line to the end. Be aware of quoting, so that $ doesn't get expanded.

You want:

ver_line_no=$(( line_no + 6 )) ver_line_text=$(sed -n "${ver_line_no}"',$p' "$1") check_if_present=$(echo "$fver_line_text" | grep "version:") 

Notes:

  • Backticks ` are deprecated. Use $( ...) command substitution instead.
  • Always quote your variables.
  • Doing echo $(( .. )) is just repeating yourself. Just $(( ... )).
  • Sometimes on systems without sed you can use cut -d $'\n' -f6-.

Comments

0

A general solution using awk (assuming that every disk has a version).

File 'find_disk_version.awk'

/disk:/ { disk_found="true" disk_name=$1 } /version:/ { if (disk_found) { print disk_name" "$2 disk_found="" } } 

Test file 'test':

 Something_else version: ver_something_else serial: blabla configuration: foo, bar *-disk:0 description: ATA Disk version: ver.0 serial: pqr *-disk:1 version: ver1 serial: pqasd configuration: pqr, abc, ghj Something_else_again version: ver_somethingelse_again serial: foobar configuration: bar, foo *-disk:2 version: ver2 serial: pqasd configuration: pqr, abc, ghj 

Output:

 $ cat test | awk -f find_disk_version.awk *-disk:0 ver.0 *-disk:1 ver1 *-disk:2 ver2 

Instead of 'cat test' can be your command 'lshw'

P.S. the script will not work if there is a disk without version.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.