AWK print if found three matches, one false - bash

There is several lines in a file that looks like:
A B C H
A B C D
and, I want to print all lines that contain this RE:
/A\tB/
But, if the line contain and H in the fourth field, do not print, the output would be:
A B C D
It could be written in one line in sed, awk or grep?
The only thing that I know is:
awk '/^A\tB/'

This will work:
awk '$1$2 == "AB" && $4 != "H"' file
If all entries are single characters this will also work:
awk '$1$2$3$4 ~ /^AB.[^H]/' file

With awk one-liner:
awk -F'\t' '$1=="A" && $2=="B" && $4!="H"' file
-F'\t' - tab char \t is treated as field separator
The output:
A B C D

This might work for you (GNU sed):
sed '/^A\tB\t.\t[^H]/!d' file
If a line does not contain A ,B ,any character and a character other than H separated by tabs, delete it.
Could be written:
sed -n '/^A\tB\t.\t[^H]/p' file

Use this.
awk '/^A\tB/ { if ( $4 != "H" ) print }'

Related

If there's match append text to the beginning of the next line

I have a file like this
from a
b
to c
d
from e
f
from g
h
to i
j
If there's match for from, add to to the beginning of the next line. If there's a match for to, add from to the beginning of the next line. The output should be like this
from a
to b
to c
from d
from e
to f
from g
to h
to i
from j
Can this be done using any unix commands?
I have tried paste command to merge every 2 lines and then using sed. Something like this. But it's definitely wrong. Also, I don't know how to split it back again.
paste -d - - <file> | sed "s/\(^from.*\)/\1 to/" | sed "s/\(^to.*\)/\1 from/"
I think there should be an easier solution to this compared to what I'm doing.
Using sed :
sed '/^from/{n;s/^/to /;b};/^to/{n;s/^/from /}'
You can try it here.
$ awk '{if ($1 ~ /^(from|to)$/) dir=$1; else $0=(dir=="from" ? "to" : "from") OFS $0} 1' file
from a
to b
to c
from d
from e
to f
from g
to h
to i
from j
Could you please try following.
awk '
{
val=prev=="from" && $0 !~ /to/?"to "$0:prev=="to" && $0 !~/from/?"from "$0:$0
prev=$1
$0=val
}
1
' Input_file
Something like this should work :
awk '
#Before reading the file I build a dictionary that links "from" keywoard to "to" value and inversally
BEGIN{kw["from"]="to"; kw["to"]="from"}
#If the first word of the line is a key of my dictionary (to or from), I save the first word in k variable and print the line
$1 in kw{k=$1;print;next}
#Else I add the "opposite" of k at the beginning of the line
{print kw[k], $0}
' <input>

Match a particular letter and print word after that using SED

I have a file "Log.txt" which look like this:
bla bla.. line1
bla bla.. line2
bla bla.. lineN
:000000 ... 239e670... A bla1.txt
:000000 ... 76fd777... M bla2.txt
:000000 ... e69de29... A bla3.txt
Let's say that I am looking for the letter 'A' and 'M'.
How would I look for it ONLY in the 4th field or line that contains this particular letter only. I need to Match the words "A" and "M" only and print the file name after that. i.e I need to get final output as below:
A bla1.txt
M bla2.txt
A bla3.txt
I used awk to match 4th column with A and M and print the next word. but not getting the expected output. I'm getting extra Bla Bla lines also.
Anyone has idea how to achieve this using sed?
awk for this:
awk '$4 ~ /^[AM]$/ { print $4," ",$5 }' Log.txt
sed for it:
sed -En '/^([^ ]+ ){3}[AM]/ { s/^([^ ]+ ){3}([AM] .*)/\2/; p; }' Log.txt
Both of these confirm that the A or M is in the 4th field.
Awk actually can do your job, just need to add a condition:
awk "/ (A|M) /{print $4,$5}" Log.txt
As for sed, you can do this:
sed -nr "/ (A|M) /{s/.*((A|M)\s+.*)$/\1/;p}" Log.txt
Not sure how are your real data looks like, but I guess you will get it and adjust the command to suit them.
As per your input file and your expected output, Please try below using awk:
awk '{if ($4 == "A" || $4 == "M") {print $4,$5}}' log.txt
Output:
A bla1.txt
M bla2.txt
A bla3.txt
This might work for you (GNU sed):
sed 's/^\(\S*\s\)\{3\}\([AM]\s\)/\2/p;d' file
Match the fourth field to be A or M and if so, remove the first three fields and print the remainder.

Awk to Add [ ] in special characters

I am trying to add [] if the column contains special characters or number except for a comma , at the end. The first line needs to be as it is in the file.
Current:
CREATE TEST
a,
b,
23_test,
Expectation:
CREATE TEST
a,
b,
[23_test],
Assuming that the special characters are digits, whitespaces, minus signs, plus signs, dots, and underscores (please modify the patten according to your definition), how about:
awk 'NR>1 && /[-0-9_+. ]/ {$0 = "[" gensub(",$", "", 1) "],"} {print}' input.txt
If you can be specific that the special characters are any characters other than alphabets and commas, try instead:
awk 'NR>1 && /[^a-zA-Z,]/ {$0 = "[" gensub(",$", "", 1) "],"} {print}' input.txt
Hope this helps.
awk 'NR>1 && /[-0-9_+. ]/ {$0 = "[" gensub(",$", "", 1) "],"} {print}' <filename.out> | sed 's/, ]/]/'
awk '{sub(/23_test/,"[23_test]")}1' file
CREATE TEST
a,
b,
[23_test],

Appending to the end of line while specific occurrence of a pattern is matched

File1:
abcxyz
b
abcxyz
abcxyz
b
c
OutputFile:
abcxyz
b
abcxyz someValueAddedHere
abcxyz
b
c
sed '/^abcxyz/ s/$/ someValueAddedHere/2' File1
Above command doesn't work for a specific occurrence, works well with all occurrences. Need to work on specified occurrence.
Thank you for the edit, Good day Sir
Following awk may help you on same. I am considering that you need the 2nd occurrence of abcxyz in Input_file where you need to insert the string. You could change the number of occurrences in code too.
awk '/abcxyz/{count++} /abcxyz/ && count==2{print $0,"someValueAddedHere";next} 1' Input_file
In case you need to save the output into Input_file itself then append > tmp_file && mv tmp_file Input_file to above code too.
sed is for doing s/old/new/, that is all. The sed constructs to do anything else became obsolete in the mid-1980s when awk was invented and are used today just for the mental exercise, not for real solutions to problems, since an awk equivalent will always be some combination of more efficient, more portable, more robust, simpler and clearer.
$ awk '/abcxyz/ && (++c == 2){$0 = $0 " someValueAddedHere"} 1' file
abcxyz
b
abcxyz someValueAddedHere
abcxyz
b
c
with sed for the mental exercise
sed '
/^abcxyz/!b
:A
$b
N
/\nabcxyz/!bA
s/$/ someValueAddedHere/
:B
n
bB
' File1
Or with gnu sed
sed -z 's/\(\nabcxyz\)/& someValueAddedHere/' File1

Replace multiple newlines with just 2 newlines using unix utilities

I have tried to look for the correct way to implement this, reading from stdin and printing to stdout. I know that I can use squeeze (-s) to delete multiple lines of the same type, but I want to leave two newlines in the place of many, not just one. I have looked into using uniq as well, but am unsure of how to. I know that fold can also be used, but I cannot find any information on the fold version I want, fold (1p).
So, if I have the text as input:
A B C D
B C D E
I would want the output to instead be
A B C D
B C D E
You can use awk like this:
awk 'BEGIN{RS="";ORS="\n\n"}1' file
RS is the input record separator, ORS is the output record separator.
From the awk manual:
If RS is null, then records are separated by sequences consisting of a newline plus one or more blank lines
That means that the above command splits the input text by two or more blank lines and concatenates them again with exactly two newlines.
Following awk may help you on same.
awk -v lines=$(wc -l < Input_file) 'FNR!=lines && NF{print $0 ORS ORS;next} NF' Input_file
OR
awk -v lines=$(wc -l < Input_file) 'FNR!=lines && NF{$0=$0 ORS ORS} NF' Input_file

Resources