Searching within column using awk - bash

I am making a contact system through a bashscript. The text file I am inputting contacts in looks like this:
Sally May,may#yahoo.com,344-555-4930,Friend
Bill,Bill#yahoo.com,344-555-6543,Co-Worker
In a search option provided I ask (after they pick the column):
echo -e"What would you like to search for:\c";;
read search
From here I would like to use the variable $search to go through the FIRST column and give me those lines in a formatted fashion. For example:
If they type in (Bill), then it should return
Name Email Phone Category
Bill Bill#yahoo.com 344-555-6543 Co-Worker
If they type in (ll), then it should return
Name Email Phone Category
Bill Bill#yahoo.com 344-555-6543 Co-Worker
Sally May may#yahoo.com 344-555-4930 Friend
The line of code I have been working on so far is this:
awk -F, '{ if ($1 ~/$search/) print $0 }' contacts.txt | awk -F, 'BEGIN{printf "%-25s %-25s %-25s %-25s\n","Name","Email","Phone","Category"} {printf "%-25s %-25s %-25s %-25\n",$1,$2,$3,$4}' ;;
It is giving me an error when I run it. Could someone help me fix this! I appreciate it

You need to pass variable to awk using -v option and need to simplify your formatting:
s='ll'
awk -F, -v s="$s" '$0 ~ s{$1=$1; print}' file | column -t
Sally May may#yahoo.com 344-555-4930 Friend
Bill Bill#yahoo.com 344-555-6543 Co-Worker
s='Bill'
awk -F, -v s="$s" '$0 ~ s{$1=$1; print}' file | column -t
Bill Bill#yahoo.com 344-555-6543 Co-Worker

read -p "What would you like to search for? :" patt
awk -F, 'BEGIN{printf "%-25s%-25s%-25s%-25s\n","Name","Email","Phone","Category"} $1~/'$patt'/{printf("%-25s%-25s%-25s%-25s\n",$1,$2,$3,$4)}' file

Related

How to awk to find and replace string in 2,3,4 and 5th column if matching pattern exist

My text file consist of 5 columns. Based on the user input want to search only in 2nd, 3rd, 4th and 5th column and replace it.
for example
oldstring="Old_word"
newstring="New_word"
So want to find all the exact match of oldstring and replace the same with newstring.
Column one should be untouched even if there is a match.
Browsed and found that awk will do but I am able to change in one particular column.
bash script
$ cat testfile
a,b,c Old_word,d,e
f,gOld_wordOld_wordOld_words,h,i,j
$ awk -F, -v OFS=, -v oldstring="Old_word" -v newstring="New_Word" '{
for (i=2; i<=5; i++) { gsub(oldstring,newstring,$i) }
print
}' testfile
a,b,c New_Word,d,e
f,gNew_WordNew_WordNew_Words,h,i,j
For more information about awk read the awk info page
Another way, similar to Glenn Jackman's answer is :
$ awk -F, -v OFS=, -v old="Old_word" -v new="New_word" '{
s=$1; $1=""; gsub(old,new,$0); $1=s
print }' <file>

Need to use awk to get a specific word or value after another specific word?

I need to use awk to get a specific word or value after another specific word, I tried some awk commands already but after many other filters like grep and sed. The file that I need to get the word from is having the same line more than one time like the below line:
Configuration: number=6 model=MSA SNT=4 IC=8 SIZE=16384MB NRF=24 meas=2.00
If need 24 I used
grep IC file | awk 'NF>1{print $NF}'
If need 16384MB I used
grep IC file | awk -F'SIZE=' '{ print $2 }'|awk '{ print $1 }'
We need to get any word from that line using awk? what I used can get what is needed but we still need a minimized awk command.
I am sure we can use one single awk to get the needed info from one line minimized command?
sed -r 's/.*SIZE=([^ ]+).*/\1/' input
16384MB
sed -r 's/.*NRF=([^ ]+).*/\1/' input
24
grep way :
grep -oP 'SIZE=\K[^ ]+' imput
16384MB
awk way :
awk '{for(i=1;i<=NF;i++) if($i ~ /SIZE=/) split($i,a,"=");print a[2]}' input
You could use an Awk with multi-character de-limiter as below to get this done. Loop through the fields, match the pattern you need and print the next field which contains the field value.
awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file
Examples,
match="number"
awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file
6
match="model"
awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file
MSA
match="meas"
awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file
2.00
here is a more general approach
... | awk -v k=NRF '{for(i=2;i<=NF;i++) {split($i,a,"="); m[a[1]]=a[2]} print m[k]}'
code will stay the same just change the key k.
If you have GNU awk you could use the third parameter of match:
$ awk 'match($0,/( IC=)([^ ]*)/,a)&& $0=a[2]' file
8
Or get the meas:
$ awk 'match($0,/( meas=)([^ ]*)/,a)&& $0=a[2]' file
2.00
Should you use some other awk, you could use this combination of split, substr and match:
$ awk 'split(substr($0,match($0,/ IC=[^ ]*/),RLENGTH),a,"=") && $0=a[2]' file
8

awk pattern match for a line with two specific words

Using AWK, want to print last line containing two specific words.
Suppose I have log.txt which contains below logs
log1|Amy|Call to Bob for Food
log2|Jaz|Call to Mary for Toy and Cookies
log3|Ron|Call to Jerry then Bob for Book
log4|Amy|Message to John for Cycle
Now, Need to extract last line with "Call" and "Bob".
I tried with-
#!/bin/bash
log="log.txt"
var="Bob"
check=$(awk -F'|' '$3 ~ "/Call.*$var/" {print NR}' $log | tail -1)
echo "Value:$check"
so Value:3 (3rd record) should be printed.
But it's not printed.Please suggest. I have to use awk.
With GNU awk for word delimiters to avoid "Bob" incorrectly matching "Bobbing":
$ awk -v var="Bob" -F'|' '$3 ~ "Call.*\\<" var "\\>"{nr=NR; rec=$0} END{if (nr) print nr, rec}' file
3 log3|Ron|Call to Jerry then Bob for Book
See http://cfajohnson.com/shell/cus-faq-2.html#Q24. If Bob is already saved in a shell variable named var then use awk -v var="$var" ....

how to make bash script that takes in one text files and outputs the data in an organised file?

I haven't done any major scripting before, but basically I'm trying to make a script that takes in a file called people.txt with data that looks like this:
Steve Wozniak:Engineer:USA:1950
And makes a new file with that data organised like this:
Name: Steve Wozniak
Occupation: Engineer
Country: USA
Date of Birth: 1950
I've given it a try using this:
cat people.txt | awk -v RS=":" '{print "Name: " $1}'
This gives me a list of every field with the title name How do I separate it?
I've got a couple more 'features' I plan on adding in, but I'm hoping I'll be able to figure those out. Would anybody be able to help me out and/or point me in the right direction?
FS is the field separator, not RS. You can set it using the -F option to awk
awk -F: '{
print "Name:", $1;
print "Occupation:", $2;
print "Country:", $3;
print "Date of Birth:", $4
}' input.txt
at least this is one way:
kent$ paste <(echo "Name\nOcuupation\nCountry\nDate of Birth") <(awk -v RS=":" '$1=$1' <<<"Steve Wozniak:Engineer:USA:1950")
Name Steve Wozniak
Ocuupation Engineer
Country USA
Date of Birth 1950
awk alone can do it too. for example, -F: -v OFS=":" '{print "Name",$1;print "Occ..",$2; print ...}'
This would work:
#!/bin/bash
while IFS=: read name job home dob
do
echo -e "Name: $name \nOccupation: $job \nCountry: $home \nDate of Birth: $dob"
echo " "
done < "$1"
Usage: % scriptname.sh filename

how can I insert a character at a certain position in a csv line

How should I go about inserting a character at a certain point in a csv line? For instance, if I had the following:
1,2,3,4,5,6,7
How could I insert ,,,,, at the spot where the 5 (fifth field) is, so it would look like
1,2,3,4,,,,,,5,6,7
I found a link for how to do this for java, but unfortunately I did not have much luck finding out how to do it with bash. Any help would be much appreciated, thanks!
You can use awk to change a specific field:
awk -F"," '{OFS=","; a=$5; $5=",,,,,",a; print $0}' file
The idea is to update the field 5 with the desired values and then print the whole line.
echo "1,2,3,4,5,6,7" | awk -F"," '{a=$5; $5=",,,,,"a; OFS=","; print}'
would print:
1,2,3,4,,,,,,5,6,7
awk -F, 'BEGIN{OFS=","}{$5=",,,,,"$5;print}' your_file
tested below:
> echo "1,2,3,4,5,6" | awk -F, 'BEGIN{OFS=","}{$5=",,,,,"$5;print}'
1,2,3,4,,,,,,5,6
>
or you can do it using perl:
> echo "1,2,3,4,5,6" | perl -F, -lane '$F[4]=~s/^/,,,,,/g;print join(",",#F)'
1,2,3,4,,,,,,5,6
>

Resources