Linux command to extract the value for a given name - linux

Suppose I have one text file(EmployeeDetails.txt) in which the content is written(all name/value in new line) as mentioned below:-
EmployeeName=XYZ
EmployeeBand=D5
EmployeeDesignation=SSE
I need the Linux command which will read this file EmployeeDetails.txt and give the value for EmployeeBand. Output should be
D5

Using grep: If anything is followed by EmployeeBand= will be printed.
grep -oP 'EmployeeBand=\K.*' EmployeeDetails.txt
Using awk where = is used as field separator and second field is printed. if search criteria is meet.
awk -F'=' '/EmployeeBand/{print $2}' EmployeeDetails.txt
Using sed ,here the band D5 is captured is a group inside () and later used using \1.
sed -r '/EmployeeBand/ s/.*=(.*$)/\1/g' EmployeeDetails.txt

Related

Find a line and modify it in a csv file given an input

I have a csv file with a list of workers and I wanna make an script for modify their work group given their ID's. Lines in CSV files are like this:
Before:
ID TAG GROUP
niub16677500;B00;AB0
After:
ID TAG GROUP
niub16677500;B00;BC0
How I can make this?
I'm working with awk and sed commands but I couldn't get anything at the moment.
With awk:
awk -F';' -v OFS=';' -v id="niub16677500" -v new_group="BC0" '{if($1==id)$3=new_group}1' input.csv
ID;TAG;GROUP
niub16677500;B00;BC0
Redirect the output to a file and note that the csv header should use the same field separator as the body.
Explanations:
-F';' to have input field separator as ;
-v OFS=';' same for the output FS
-v id="niub16677500" -v new_group="BC0" define the variables that you are going to use in the awk commands
'{if($1==id)$3=new_group}1' when the first column is equal to the value contained in variable id the overwrite the 3rd field and print the line
With sed:
id="niub16677500"; new_group="BC0"; sed "/^$id/s/;[^;]*$/;$new_group/" input.csv
ID;TAG;GROUP
niub16677500;B00;BC0
You can either do an inline change using -i.bak option, or redirect the output to a file.
Explanations:
Store the values in 2 variables
/^$id/ when you reach a line that starts with the ID store in the variable id, run sed search and replace
s/;[^;]*$/;$new_group/ search and replace command that will replace the last field by the new value
Sed can do it,
echo 'niub16677500;B00;AB0' | sed 's/\(^niub16677500;...;\)\(...\)$/\1BC0/'
will replace the AB0 group in your example with BC0, by matching the user name, semicolon, whatever 3 characters and another semicolon, and then matching the remaining 3 characters. Then as an output it repeats the first match with \1 and adds BC0.
You can use :
sed 's/\(^niub16677500;...;\)\(...\)$/\1BC0/' <old_file >new_file
to make a new_file with this change.
https://www.grymoire.com/Unix/Sed.html is a great resource, you should take a look at it.

Extract data between two words using sed or awk

I have a log file and I am trying to extract data between 2 words of that log file.
username=#$^#$^&###%^&==&employeeid
There is data before and after these words but I am only interested in the data between them. Thus the expected output is (just the value between the username= and &employeeid
#$^#$^&###%^&==
I want to grep the file first and then search using sed in that file. Something like below. This is not working for me exactly..
grep "e553bb57-b94b-cb0f-f4ba-eb9a02ab0050" /path/abc/logfile.txt | sed -n '/username=/{s/.*username=//;s/\S*=.*//;p}'
How about
echo 'username=#$^#$^&###%^&==&employeeid' | sed 's/username=\(.*\)==&employeeid/\1/'
The output is
#$^#$^&###%^&
The matched part would be in \1.

awk is not picking string and pipe as delimiter

I have a file where each record has a word "TST_BI|" and I need to use as a delimiter and populate the value after this string to a file . There is only one occurrence of this string in each record.
It is working fine in AIX environment with below command.
awk -F "TST_BI|" '{print $2}' file.txt.
But when I migrated the code to Linux and tried the same, command is NOT working, where the value "|" is also getting populated. Below are the output from both AIX and Linux
Input :
<14>1 2017-08-31T04:13:47.2345839+00:00 loggregator ecsdasc0985-cs656-4asdsds-asds-asdasg6ds73 [DEV/2] - - TST_BI|DATE~2017-08-31 04:13:47,095|TIMESTAMP~04:13:47|TEST_ID~biTestExecutor-2|COUNTRY_CODE~XX|GROUP_TESTS~BZAG
OutPut from AIX :
DATE~2017-08-31 04:13:47,095|TIMESTAMP~04:13:47|TEST_ID~biTestExecutor-2|COUNTRY_CODE~XX|GROUP_TESTS~BZAG
With same command,
Linux Output is
|DATE~2017-08-31 04:13:47,095|TIMESTAMP~04:13:47|TEST_ID~biTestExecutor-2|COUNTRY_CODE~XX|GROUP_TESTS~BZAG
A pipe is getting populated and which is not treating as delimiter.
Can anyone please help?
vertical bar char | specified with adjacent characters is treated as regex alternation operator/alternation group. In such case, to treat | literally - it should be escaped \\| or put into a character class [|]:
awk -F'TST_BI[|]' '{print $2}' file.txt
The output:
DATE~2017-08-31 04:13:47,095|TIMESTAMP~04:13:47|TEST_ID~biTestExecutor-2|COUNTRY_CODE~XX|GROUP_TESTS~BZAG

How to use grep and sed in order to replace the substring after searching some specific string?

I want to know how to use two 'grep' and 'sed' utilities or something else in order to replace the substring. I will explain what I want to do below.
We have the file 'test.txt' with the following string:
A1='AA1', A2='AA2', A3='AA3', A4='AA4', A5{ATTR}='AA5', A6='keyword_A'
After searching 'keyword_A' using grep, I want to replace the value of A5 with other string, for example, "NEW".
A1='AA1', A2='AA2', A3='AA3', A4='AA4', A5{ATTR}='NEW', A6='keyword_A'
I tried to use two commands like
grep keyword_A test.txt | sed -e 's/blabla/blabla/'
After trying all I know, I gave up at all.
Please let me know the right solution.
First, you never need grep and sed. Sed has a full regular-expression search engine, so it is a superset of grep. This command will read test.txt, change the lines that you've indicated, and print the entire result on standard output:
sed "/keyword_A/s/A5{ATTR}='[A-Z0-9]*'/A5{ATTR}='NEW'/g" < test.txt
If you want to store the results back into the file test.txt, use the -i (in-place editing) switch to sed:
sed "/keyword_A/s/A5{ATTR}='[A-Z0-9]*'/A5{ATTR}='NEW'/g" -i.bak test.txt
If you want to select only the indicated lines, modify those, and print only those lines to standard out, use a combination of the p (print) command and the -n (no output) switch.
sed "/keyword_A/s/A5{ATTR}='[A-Z0-9]*'/A5{ATTR}='NEW'/gp" -n test.txt
Using grep+sed is always the wrong approach. Here's one way to do it with GNU awk:
$ awk '/keyword_A/{ $0=gensub(/(A5({[^}]+})?=\047)[^\047]+/,"\\1NEW",1) } 1' file
A1='AA1', A2='AA2', A3='AA3', A4='AA4', A5{ATTR}='NEW', A6='keyword_A'
Using a couple variables you could define the keyword and replacement ( if they change at all ):
q="keyword_A"
r="NEW"
Then with sed:
sed -r "s/^(.+\{.+\}=')(.+)('.+"${q}".+)$/\1"${r}"\3/" file
Result:
A1='AA1', A2='AA2', A3='AA3', A4='AA4', A5{ATTR}='NEW', A6='keyword_A'
A5="NEW"
A6="keyword_A"
# with sed
sed "s/='[^']*\(',[[:blank:]]*A6='${A6}'\)/='${A5}\1/" YourFile
# with awk
awk -F "'" -v A5="${A5}" -v A6="${A6}" '
BEGIN { OFS="\047" }
$12 == A6 { $10 = A5; $0 = $0 }
7
' YourFile
Change by the end of the string, for sed and using ' as field separator in awk instead of traditional space.
assuming there is no ' in value (or need to treat the escaping method) for awk version
We can just directly replace the fifth column when the sting keyword_A is found as shown below:
awk -F, 'BEGIN{OFS=",";}/keyword_A/{$5="A5{ATTR}='"'"NEW"'"'"}1' filename
Couple of slight alternatives:
sed -r "/keyword_A/s/(A5[^']*')[^']*/\1NEW/"
awk -F"'" '/keyword_A/{$10 = "NEW"}1' OFS="'"
Of course the negative with awk is afterwards you would have to rename the new file.

Extracting key word from a log line

I have a log which got like this :
.....client connection.....remote=/xxx.xxx.xxx.xxx]].......
I need to extract all lines in the log which contain the above,and print just the ip after remote=.. This would be something in the pattern :
grep "client connection" xxx.log | sed -e ....
Using grep:
grep -oP '(?<=remote=/)[^\]]+' file
o is to extract only the pattern, instead of entire line.
P is to match perl like regex. In this case, we are using "negative look behind". It will try to match set of characters which is not "]" which is preceeded by remote=/
grep -oP 'client connection.*remote=/\K.*?(?=])' input
Prints anything between remote=/ and closest ] on the lines which contain client connection.
Or by using sed back referencing: Here the line is divided into three parts/groups which are later referred by \1 \2 or \3. Each group is enclosed by ( and ). Here IP address belongs to 2nd group, so whole line is replaced by 2nd group which is IP address.
sed -r '/client connection/ s_(^.*remote=/)(.*?)]](.*)_\2_g' input
Or using awk :
awk -F'/|]]' '/client connection/{print $2}' input
Try this:
grep 'client connection' test.txt | awk -F'[/\\]]' '{print $2}'
Test case
test.txt
---------
abcd
.....client connection.....remote=/10.20.30.40]].......
abcs
.....client connection.....remote=/11.20.30.40]].......
.....client connection.....remote=/12.20.30.40]].......
Result
10.20.30.40
11.20.30.40
12.20.30.40
Explanation
grep will shortlist the results to only lines matching client connection. awk uses -F flag for delimiter to split text. We ask awk to use / and ] delimiters to split text. In order to use more than one delimiter, we place the delimiters in [ and ]. For example, to split text by = and :, we'd do [=:].
However, in our case, one of the delimiters is ] since my intent is to extract IP specifically from /x.x.x.x] by spitting the text with / and ]. So we escape it ]. The IP is the 2nd item from the splitting.
A more robust way, improved over this answer would be to also use GNU grep in PCRE mode with -P for perl style regEx match, but matching both the patterns as suggested in the question.
grep -oP "client connection.*remote=/\K(\d{1,3}\.){3}\d{1,3}" file
10.20.30.40
11.20.30.40
12.20.30.40
Here, client connection.*remote matches both the patterns in the lines and extracts IP from the file. The \K is a PCRE syntax to ignore strings up to that point and print only the capture group following it.
(\d{1,3}\.){3}\d{1,3}
To match the IP i.e. 3 groups of digits separated by dots of length from 1 to 3 followed by 4th octet.

Resources