Suhasini Subramaniam
Suhasini Subramaniam

Reputation: 161

how to write a bash for loop to create a template

how to write a bash for loop to create a template

Source File:

    "INTEL SSDPEL1D380GA                   CCCCCCCCCCCCCCC    01",
    "Samsung SSD 970 PRO 1TB               XXXXXXXXXXXXXXX     01",
    "Samsung SSD 970 PRO 1TB               YYYYYYYYYYYYYYY     01",
    "Samsung SSD 970 PRO 1TB               ZZZZZZZZZZZZZZZ     01",
    "Samsung SSD 970 PRO 1TB               IIIIIIIIIIIIIII     01"

Desired Output:

node_nvme_device{manufacturer="INTEL",partnumber="SSDPEL1D380GA",serialnumber="CCCCCCCCCCCCCCC"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="XXXXXXXXXXXXXXX"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="YYYYYYYYYYYYYYY"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="ZZZZZZZZZZZZZZZ"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="IIIIIIIIIIIIIII"} 1

My attempted and failed code

awk 'NF>1 {
"node_nvme_device{manufacturer="$1",partnumber="$2",serialnumber="$3"} 1" }' source_file

Upvotes: 1

Views: 918

Answers (4)

anubhava
anubhava

Reputation: 785581

Here is another awk alternative:

awk '
{
   mf = $1
   sn = $(NF-1)
   gsub(/^[[:blank:]]*"[^[:blank:]]+[[:blank:]]+|[[:blank:]]{2,}[[:alnum:]].*$/, "")
   printf "node_nvme_device{manufacturer=%s\",partnumber=\"%s\",serialnumber=\"%s\"} 1\n", mf, $0, sn
}' file

node_nvme_device{manufacturer="INTEL",partnumber="SSDPEL1D380GA",serialnumber="CCCCCCCCCCCCCCC"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="XXXXXXXXXXXXXXX"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="YYYYYYYYYYYYYYY"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="ZZZZZZZZZZZZZZZ"} 1
node_nvme_device{manufacturer="Samsung",partnumber="SSD 970 PRO 1TB",serialnumber="IIIIIIIIIIIIIII"} 1

Upvotes: 2

Shakiba Moshiri
Shakiba Moshiri

Reputation: 23864

It is possible to use a one-liner e.g. Perl but using a shell script you will have more / better flexibility, scalability, maintenance of your code for later use cases.

The proper solution will be in two major steps:

  1. first read the file into an array
  2. read each line as an new array

So for part 1 you can use mapfile built-in bash command to read all the lines of the file you have into an array.

#!/bin/bash
mapfile -t arr < file.txt

Now you will have an array of each line e.g. echo ${arr[0]} will print your first line and echo ${arr[@]} will print all lines. Then you can read each line (step 2) into an other array and use them:

#!/bin/bash

# read all lines
mapfile -t arr < file.txt

# read just line 1
mapfile -t line1 < <(echo ${arr[0]} | tr ' ' '\n')

# print first element of line 1
echo ${line1[0]}

# output
"INTEL

then you can refactor these two steps to your own specific one.


Please notice you do not have to use the second mapfile (step 2) manually and you can use a for-loop for reading first array (array of lines) e.g.

for line in ${arr[@]}; do
    # read each line into an new array
    mapfile -t each_line < <(echo ${line[@]} | tr ' ' '\n');
     
    # do whatever you need to do with each line
    echo "each line: ${each_line[@]}";
done

Plus you should get rid of extra characters in the file e.g. " , ,, etc. before using the contents / values.

Upvotes: 3

Raman Sailopal
Raman Sailopal

Reputation: 12887

Assuming that the data is tab delimited and using Python:

#!/usr/bin/python
for f in open("parts"):                                # Open a file called parts
   f=f.replace("\"","")                                # Remove quotes from the line
   f=f.replace(",","")                                 # Remove commas from the line
   bits=f.split("\t")                                  # Split the line into the array bits based on tabs
   bits1=bits[0].split(" ")                            # Split the first index further into bits1 this time using " "
   stryng=bits1[0]
   numb=int(bits[2])
   for i in range(1,len(bits1),1):                     # Loop through bit1, building a strinf stryng
      stryng=stryng + " " + bits1[i]
   print("node_nvme_device{manufacturer=\"" + bits1[0] + "\",partnumber=\"" + stryng + "\",serialnumber=\"" + bits[1] + "\"} " + str(numb))       # Print the data in format required

Upvotes: 0

RavinderSingh13
RavinderSingh13

Reputation: 133630

With your shown samples only, could you please try following.

awk '
match($0,/".*               /){
  val1=""
  val=substr($0,RSTART+1,RLENGTH-1)
  sub(/[[:space:]]+$/,"",val)
  num=split(val,arr," ")
  for(i=2;i<=num;i++){
    val1=(val1?val1 OFS:"")arr[i]
  }
  printf("node_nvme_device{manufacturer=\"%s\",partnumber=\"%s\",serialnumber=\"%s\"} %01d\n",arr[1],val1,$(NF-1),$NF)
}' Input_file

Explanation: Simply using match function of awk to match from starting to till bigger space as per shown samples, then saving its matched sub string into val, removing spaces to get rid of it, then creating val2 which has al values from 2nd element to till end of array here(since there are multiple values in samples by OP eg--> SSD 970 PRO 1TB to match here), then finally printing the values as per needed output using printf, simply passing values(fields of current line and array's element with val1 value here).

Upvotes: 3

Related Questions