How to do something like this in linux shell script - linux

I have a shell script that is doing something.I want to print the Unknown string where there is blank space in the output.
I want to do check if (f[1] == "") or (f[2] == "") or (f[3] == ""), it should be replaced by a unknown string and should be written in a single file
if(f[1] == "") printf(fmt, id, f[1], f[2], f[3]) > file
where f[1],f[2],f[3] if empty should be replaced by unknown string
where f[1] is the first index, fmt is the format specifier I have defined in the code.How to replace these empty spaces with a string in Linux.
Any lead is appreciated.
Thanks

Use the conditional operator:
ec2-describe-instances | awk -F'\t' -v of="$out" -v mof="$file" '
function pr() { # Print accumulated data
if(id != "") { # Skip if we do not have any unprinted data.
printf(fmt, id, f[1], f[2], f[3]) > of
if (f[1] == "" || f[2] == "" || f[3] == "") {
printf(fmt, id, f[1]==""?"Unknown":f[1], f[2]==""?"Unknown":f[2], f[3]==""?"Unknown":f[3]) > mof
}
}
# Clear accumulated data.
id = f[1] = f[2] = f[3] = ""
}
BEGIN { # Set the printf() format string for the header and the data lines.
fmt = "%-20s %-40s %-33s %s\n"
# Print the header
headerText="Instance Details"
headerMaxLen=100
padding=(length(headerText) - headerMaxLen) / 2
printf("%" padding "s" "%s" "%" padding "s" "\n\n\n", "", headerText, "") > of
printf(fmt, "Instance id", "Name", "Owner", "Cost.centre") > of
printf("%" padding "s" "%s" "%" padding "s" "\n\n\n", "", headerText, "") > mof
printf(fmt, "Instance id", "Name", "Owner", "Cost.centre") > mof
}
$1 == "TAG" {
# Save the Instance ID.
id = $3
if($4 ~ /[Nn]ame/) fs = 1 # Name found
else if($4 ~ /[Oo]wner/) fs = 2 # Owner found
else if($4 ~ /[Cc]ost.[Cc]ent[er][er]/) fs = 3 # Cost center found
else next # Ignore other TAGs
f[fs] = $5 # Save data for this field.
}
$1 == "RESERVATION" {
# First line of new entry found; print results from previous entry.
pr()
}
END { # EOF found, print results from last entry.
pr()
}'

Related

Print a specific words till matched string ( pattern 2 )above the matched string ( pattern 1 ) in a file

object Host "os.google.com" {
import "windows"
address = "linux.google.com"
groups = ["linux"]
}
object Host "mango.google.com" {
import "windows"
address = "mango.google.com"
groups = ["linux"]
assign where "mango" in Hostgroups
}
I want to print the lines above the matched string till the specific pattern in a file
Ex:
I want to print the lines above the assign where "mango" in Hostgroups till this pattern { in the file
Desired output:
object Host "mango.google.com" {
import "windows"
address = "mango.google.com"
groups = ["linux"]
assign where "mango" in Hostgroups
Try this awk script
script.awk
/{/,/}/ { #define record range from { to }
if ($0 ~ "{") rec = $0; # if record opening reset rec variable with current line
else rec = rec "\n" $0; # else accumulate the current line in rec
if ($0 ~ /assign where "mango" in Hostgroups/) { # if found exit pattern in current line
print rec; # print the rec
exit; # terminate
}
}
executions:
awk -f script.awk input.txt
output:
object Host "mango.google.com" {
import "windows"
address = "mango.google.com"
groups = ["linux"]
assign where "mango" in Hostgroups

How to combine two line by matching the pattern in shell script

I was trying to combine the two lines.
example of my data is ::
Hello Reach World Test
Reach me Test out .
I would like to combine this as ::
Output
Hello Reach World Test Reach me Test out .i.e Only if last word matches Test and Begin matches Reach .
I was trying with
awk '/Test$/ { printf("%s\t", $0); next } 1' .
Could anyone please let me know how to match it and combine.
Does this awk script do what you want:
BEGIN { flag = "0"; line = "" }
{
if ( flag == "1" ) {
if ( $0 ~ "^Reach" )
print line " " $0
else {
print line
print $0
}
line = ""
flag = "0"
} else {
if ( $0 ~ "Test$" ) {
line = $0
flag = "1"
} else
print $0
}
}

how to iterate over two sets of data?

I'm trying to create my own program to do a recursive listing: each line corresponds to the full path of a single file. The tricky part I'm working on now is: I don't want bind mounts to trick my program into listing files twice.
So I already have a program that produces the right output except that if /foo is bind mounted to /bar then my program incorrectly lists
/foo/file
/bar/file
I need the program to list just what's below (EDIT: even if it was asked to list the contents of /foo)
/bar/file
One approach I thought of is to mount | grep bind | awk '{print $1 " " $3}' and then iterate over this to sed every line of the output, then sort -u.
My question is how do I iterate over the original output (a bunch of lines) and the output from mount (another bunch of lines)? (or is there a better approach) This needs to be POSIX (EDIT: and work with /bin/sh)
Place the 'mount | grep bind' command into the AWK within a BEGIN block and store the data.
Something like:
PROG | awk 'BEGIN{
# Define the data you want to store
# Assign to global arrays
command = "mount | grep bind";
while ((command | getline) > 0) {
count++;
mount[count] = $1;
mountPt[count] = $3
}
}
# Assuming input is line-by-line and that mountPt is the value
# that is undesired
{
replaceLine=0
for (i=1; i<=count; i++) {
idx = index($1, mountPt[i]);
if (idx == 1) {
replaceLine = 1;
break;
}
}
if (replaceLine == 1) {
sub(mountPt[i], mount[i], $1);
}
if (printed[$1] != 1) {
print $1;
}
printed[$1] = 1;
} '
Where I assume your current program, PROG, outputs to stdout.
find YourPath -print > YourFiles.txt
mount > Bind.txt
awk 'FNR == NR && $0 ~ /bind/ {
Bind[ $1] = $3
if( ( ThisLevel = split( $3, Unused, "/") - 1 ) > Level) Level = ThisLevel
}
FNR != NR && $0 !~ /^ *$/ {
RealName = $0
for( ThisLevel = Level; ThisLevel > 0; ThisLevel--){
match( $0, "(/[^/]*){" ThisLevel "}" )
UnBind = Bind[ substr( $0, 1, RLENGTH) ]
if( UnBind !~ /^$/) {
RealName = UnBind substr( $0, RLENGTH + 1)
ThisLevel = 0
}
}
if( ! File[ RealName]++) print RealName
}
' Bind.txt YourFiles.txt
search based on a exact path/bind comparaison from a bind array loaded first
Bind.txt and YourFiles.txt could be a direct redirection to be "1" instruction and no temporary files
have to be adapted (first part of awk) if path in bind are using space character (assume not here)
file path are changed live when reading, compare to an existing bind relation
print file if not yet known

Generate JSON using Dynamic Variable in Shell script

I need to generate JSON output from my shell script.
I need to get Ram slot details of a particular machine and generate JSON using those details.
To get Ram details I am using system_profiler SPMemoryDataType
It produces details as follows.
BANK 0/DIMM0:
Size: 2 GB
Type: DDR3
Speed: 1600 MHz
Status: OK
Manufacturer: 0x802C
Part Number: 0x384A54463235363634485A2D3147364D3120
Serial Number: 0xE98388E6
BANK 1/DIMM0:
Size: 2 GB
Type: DDR3
Speed: 1600 MHz
Status: OK
Manufacturer: 0x802C
Part Number: 0x384A54463235363634485A2D3147364D3120
Serial Number: 0xE98388E5
From that I should form JSON like this
[
{"Bank":"0/DIMM0","Serial Number":"0xE98388E6","Status":"OK"},
{"Bank":"1/DIMM0","Serial Number":"0xE98388E5","Status":"OK"}
]
To extract separate details like bank, Serial Number, Status we can use
system_profiler SPMemoryDataType | awk '/Bank/
system_profiler SPMemoryDataType | awk '/Serial/
system_profiler SPMemoryDataType | awk '/Status/
I am sure that there is a need of Dynamic variable to do form json from the results. But since I am new to shell script I am confused. Is there any way to generate JSON from the output?
#!/usr/bin/awk -f
$1 == "BANK" {
bank = $2
sub(/:/, "", bank)
while (getline > 0) {
if ($1 == "Serial" && $2 == "Number:") {
serial_number = $3
} else if ($1 == "Status:") {
status = $2
}
if (serial_number != "" && status != "") {
entries[++e] = "{\"Bank\":\"" bank "\",\"Serial Number\":\"" serial_number "\",\"Status\":\"" status "\"}"
break
}
}
bank = serial_number = status = ""
}
END {
print "["
if (e > 0) {
printf "%s", entries[1]
for (i = 2; i <= e; ++i) {
printf ",\n%s", entries[i]
}
print ""
}
print "]"
}
Usage:
awk -f script.awk file
system_profiler SPMemoryDataType | awk -f script.awk
Example output:
[
{"Bank":"0/DIMM0","Serial Number":"0xE98388E6","Status":"OK"},
{"Bank":"1/DIMM0","Serial Number":"0xE98388E5","Status":"OK"}
]
Using within a shell script:
#!/bin/bash
system_profiler SPMemoryDataType | awk '$1 == "BANK" {
bank = $2
sub(/:/, "", bank)
while (getline > 0) {
if ($1 == "Serial" && $2 == "Number:") {
serial_number = $3
} else if ($1 == "Status:") {
status = $2
}
if (serial_number != "" && status != "") {
entries[++e] = "{\"Bank\":\"" bank "\",\"Serial Number\":\"" serial_number "\",\"Status\":\"" status "\"}"
break
}
}
bank = serial_number = status = ""
}
END {
print "["
if (e > 0) {
printf "%s", entries[1]
for (i = 2; i <= e; ++i) {
printf ",\n%s", entries[i]
}
print ""
}
print "]"
}'
A one-liner:
system_profiler SPMemoryDataType | awk '$1=="BANK"{bank=$2;sub(/:/,"",bank);while(getline>0){if($1=="Serial"&&$2=="Number:"){serial_number=$3}else if($1=="Status:"){status=$2};if(serial_number!=""&&status!=""){entries[++e]="{\"Bank\":\""bank"\",\"SerialNumber\":\""serial_number"\",\"Status\":\""status"\"}";break}};bank=serial_number=status=""}END{print "[";if(e>0){printf "%s",entries[1];for(i=2;i<=e;++i){printf ",\n%s",entries[i]};print""};print "]"}'
There are some few libraries to do so.. One such thing is https://github.com/jeganathgt/libjson-sh . It is standalone shell script library, provides easy handy API's to generate json output in console.
Ex :
json_init
json_add_string "serial" "$<cmd>"
json_add_string "bankinfo" "$<cmd>"
json_add_string "status" "$<cmd>"
json_dump

search 2 files and output the common and print an extra line unix scripting

I have this code, but it's giving me an error
awk '
FNR == NR {
# reading get_ids_only.txt
values[$1] = ""
next
}
BEGIN {
# reading default.txt
for (elem in values){
if ($0 ~ elem){
if (values[elem] == ""){
values[elem] = "\"" $0 "\""
getline;
values[elem] = "\n"" $0 ""\n"
}
else{
values[elem] = values[elem] ", \"" $0 "\""
getline;
values[elem] = values[elem] "\n"" $0 ""\n"
}
}
}
END {
for (elem in values)
print elem " [" values[elem] "]"
}
' get_ids_only.txt default.txt
The error says
awk: syntax error at source line 23
context is
>>> END <<< {
awk: illegal statement at source line 24
awk: illegal statement at source line 24
missing }
This is where my END{ } function starts...
What I'm trying to do is.. compare the string.... in file 1.. if the string is found in file 2, print the string and print the line after it as well., then skip a space.
input1:
message id "hello"
message id "good bye"
message id "what is cookin"
input2:
message id "hello"
message value "greetings"
message id "good bye"
message value "limiting"
message id "what is there"
message value "looking for me"
message id "what is cooking"
message value "breakfast plate"
output:
should print out all the input1, grabbing the message value from input 2.
can anyone guide me on why this error is occurring?
I'm using the terminal on my mac.
Here's your BEGIN block with recommended indention and comments, can you see the problem?
BEGIN {
# reading default.txt
for (elem in values){
if ($0 ~ elem){
if (values[elem] == ""){
values[elem] = "\"" $0 "\""
getline;
values[elem] = "\n"" $0 ""\n"
}
else{
values[elem] = values[elem] ", \"" $0 "\""
getline;
values[elem] = values[elem] "\n"" $0 ""\n"
} # End inner if
} # End outer if
} # End for loop
Your missing a closing brace. Note that in the final concatenation with $0, $0 is actually quoted.
There are some other issues with this, I'm not sure what you are trying to do, but it seems a very un-awky approach. Usually if you find yourself overusing getline, you should be thinking about spreading the code into separate blocks with appropriate conditions. See this article on the uses an misuses of getline for more.
A more awky way to solve it
If I understand you correctly, this is the way I would solve this task:
extract.awk
FNR==NR { id[$0]; next } # Collect id lines in the `id' array
$0 in id { f=1 } # Use the `f' as a printing flag
f # Print when `f' is 1
NF==0 { f=0 } # Stop printing after an empty line
Run it like this:
awk -f extract.awk input1 input2
Output:
message id "hello"
message value "greetings"
message id "good bye"
message value "limiting"

Resources