How to get the rest of the Pattern using any linux command? - linux

I am try to update a file and doing some transformation using any linux tool.
For example, here I am trying with awk.
Would be great to know how to get the rest of the pattern?
awk -F '/' '{print $1"/raw"$2}' <<< "string1/string2/string3/string4/string5"
string1,rawstring2
here I dont know how many "/" is there and I want to get the output:
string1/rawstring2/string3/string4/string5

Something like
awk -F/ -v OFS=/ '{ $2 = "raw" $2 } 1' <<< "string1/string2/string3/string4/string5"
Just modify the desired field, and print out the changed line (Have to set OFS so it uses a slash instead of a space to separate fields on output, and a pattern of 1 uses the default action of printing $0. It's an idiom you'll see a lot of with awk.)

Also possible with sed:
sed -E 's|([^/]*/)|\1raw|' <<< "string1/string2/string3/string4/string5"
The \1 in the replacement string reproduces the bit inside parenthesis and appends raw to it.
Equivalent to
sed 's|\([^/]*/\)|\1raw|' <<< "string1/string2/string3/string4/string5"

Related

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.

Separate a text file with sed

I have the following sample file:
evtlog.161202.002609.debugevtlog.161201.162408.debugevtlog.161202.011046.debugevtlog.161202.002809.debugevtlog.161201.160035.debugevtlog.161201.155140.debugevtlog.161201.232156.debugevtlog.161201.145017.debugevtlog.161201.154816.debug
I want to separate the string and add a newline after matching "debug" like this:
evtlog.161202.002609.debug
evtlog.161201.162408.debug
So far I tried almost everything with sed, but it doesn't seem to do what I want.
sed 's/debug/{G}' latest_evtlogs.out
sed '/debug/i "SAD"' latest_evtlogs.out
etc...
sed 's/debug/\n/g' latest_evtlogs.out doesn't work when I add it as a pipe in the script , but it does when I run it manually.
Here's how I generate the file:
printf $(ls -l $EVTLOG_PATH/evtlog|tail -n 10|awk '{printf $8 , "%s\n\n"}'|sed 's/debug/\n/g') >> latest_evtlogs.out
Initially I wanted to just add newline with awk, but it doesn't work either.
Any ideas why I can't separate the string with a newline ?
I'm using :
Distributor ID: Debian
Description: Debian GNU/Linux 5.0.10 (lenny)
Release: 5.0.10
Codename: lenny
Just add a new line after debug:
sed 's/debug/&\n/g' file
Note & prints back the matched text, so it is a way to print "debug" back.
This returns:
evtlog.161202.002609.debug
evtlog.161201.162408.debug
evtlog.161202.011046.debug
evtlog.161202.002809.debug
evtlog.161201.160035.debug
evtlog.161201.155140.debug
evtlog.161201.232156.debug
evtlog.161201.145017.debug
evtlog.161201.154816.debug
The problem is, that you are using the output of sed in a command expansion. In this context your shell will replace all newlines with spaces. The spaces are then used to do the word splitting, so that printf sees each line as a separate argument, interpreting the first line as the format argument and ignoring the rest as there are printf-placeholders in the format.
It should work if you drop the outer printf $() from your command and just redirect the output from your pipeline to your file:
ls -l $EVTLOG_PATH/evtlog|tail -n 10|awk '{printf $8 , "%s\n\n"}'|sed 's/debug/\n/g' >> latest_evtlogs.out
Maybe Perl is "happier" than sed on your system:
perl -pe 's/debug/&\n/g' < YourLogFile
Get will append what is in the hold buffer unto the pattern space (Usually just the current line read from the input file) So this cannot be used.
insert will print the specified text to standard output. So this cannot be used.
What you you want to to replace all debug with debug^J, where ^J is a newline, dependent on the sed version, you can either do:
sed 's/debug/&\n/g' input_file
But \n is - afaik - not strictly specified in POSIX sed. One can however use c strings:
sed 's/debug/&'$'\n''/g' input_file
Or a multi line string:
sed 's/debug/&\
/g' input_file
Thank you all for the answers.I finally did it like this :
echo $(ls -l $EVTLOG_PATH/evtlog|tail -n 10|awk '{printf $8 , "%s\n\n"}'|sed 's/debug/&\n/g') > temp.out
sed 's/ /\n/g' /share/sqa/dumps/5314577631/checks/temp.out > latest_evtlogs.out
It's not at all elegant, but it finally works.

Why am I getting this error when trying to use sed command to delete string?

I am trying to use sed to delete a string from a given file. The string to be removed is stored in password. Here is what I have
sed -i "s/$password//g" shadowCopy.txt
It keeps telling me
sed: -e expression #1, char 0: no previous regular expression
I understand that it is yelling at me for the blank in the spot designated for the replacement regular expression, but I don't want to replace it with anything. Lots of looking online says that I'm doing it the way i should be. Any guesses?
I have also tried blank=""
sed -i "s/$password/$blank/g" shadowCopy.txt which gives me the same error. I have also looked at maybe using awk somehow, but cant figure out a way. Really any suggestion as to a way to delete a string in a file will satisfy
EDIT: Using the suggestion below my code is as follows
#Retrieve the root password hash from shadowCopy
password= awk -F: '$1=="root" {print $2}' shadowCopy.txt
#Remove the root password
pw="$password" perl -pe 'BEGIN { $search = quotemeta($ENV{pw}); } s/$search//g' shadowCopy.txt
and my output is
$1$aj/Pot/V$H4A7chbz7rfsRIrdL7GO61 //This is the password
root:$1$aj/Pot/V$H4A7chbz7rfsRIrdL7GO61:16469:0:99999:7:::
bin:*:16229:0:99999:7:::
Why is the password being printed out? And obviously when the file contents are dumped to show the changes, the password is still there. If i add echo $password nothing prints so clearly it isn't being properly intialized. Obviously the code in my assignment line works somewhat as it prints out what i'm wanting but it isnt storing it in the variable
RESOLVED: cp shadowCopy.txt shadowCopy.txt~ && awk 'BEGIN{FS=OFS=":"} $1=="root"{$2=""}1' shadowCopy.txt~ > shadowCopy.txt && rm shadowCopy.txt~ is what actually ended up doing it for me. In case anyone in the future cares to know
The problem is that sed cannot operate on strings, only on regexps with some additional restrictions. This will work:
awk -v tgt="$password" 's=index($0,tgt){$0 = substr($0,1,s-1) substr($0,s+length(tgt)}1' file
because it's using only string operations.
Given your newly posted information, you want this:
awk 'BEGIN{FS=OFS=":"} $1=="root"{$2=""} 1' shadowCopy.txt > tmp$$ &&
mv tmp$$ shadowCopy.txt
or if you have GNU awk and care about not naming the tmp file:
awk -i inplace 'BEGIN{FS=OFS=":"} $1=="root"{$2=""} 1' shadowCopy.txt
It happens when your variable is resolved to an empty string. Look:
p="a" && sed "s/$p/?/g" infile
That yields:
J?n 16 08:33:18 m?il.
And:
p="" && sed "s/$p//" infile
That yields:
sed: -e expression #1, char 0: no previous regular expression

Running awk on file, with regular expressions

I would like to find all occurrences of INPUT in a file, JUST INPUT. I have the following, but it finds everything with INPUT*
awk '{for(i=1;i<=NF;i++){if($i~/^INPUT/){print $i}}}'
I would like to support that though, so if I have INPUT* or INPUT? or INPUT. (any regular expression) instead of INPUT in the above, it should work for that.
Anyone know how to fix the above to do that? Thanks.
I'm trying to do the following in a perl script using $INPUT
`awk '{for(i=1;i<=NF;i++){if($i~/^$INPUT$/){print $i}}}' $file`
but I can't get it to work any ideas?
If you want to use backticks, then escape all dollar signs (assuming you have something, e.g., 'INPUT' in $INPUT)::
`awk '{for(i=1;i<=NF;i++){if(\$i~/^$INPUT\$/){print \$i}}}' $file | wc -l`;
awk can count the number of matches for you too (this one counts once one per line):
`awk '/\y$INPUT\y/{s++} END{print s}' $file`;
and using native Perl, which is recommended:
my $cnt;
open my $f, "<", "input" or die("$!");
while (<$f>) {
$cnt++ while /\bINPUT\b/g;
}
close $f;
print $cnt;
The regular expression you use is achored at the beginning ^ but not the end $. Try:
awk '{for(i=1;i<=NF;i++){if($i~/^INPUT$/){print $i}}}'
If you want to match INPUT anywhere in the field, try:
awk '{for(i=1;i<=NF;i++){if($i~/INPUT/){print $i}}}'

Linux scripting: Search a specific column for a keyword

I have a large text file that contains multiple columns of data. I'm trying to write a script that accepts a column number and keyword from the command line and searches for any hits before displaying the entire row of any matches.
I've been trying something along the lines of:
grep $fileName | awk '{if ($'$columnNumber' == '$searchTerm') print $0;}'
But this doesn't work at all. Am I on the right lines? Thanks for any help!
The -v option can be used to pass shell variables to awk command.
The following may be what you're looking for:
awk -v s=$SEARCH -v c=$COLUMN '$c == s { print $0 }' file.txt
EDIT:
I am always trying to write more elegant and tighter code. So here's what Dennis means:
awk -v s="$search" -v c="$column" '$c == s { print $0 }' file.txt
Looks reasonable enough. Try using set -x to look at exactly what's being passed to awk. You can also use different and/or more awk things, including getting rid of the separate grep:
awk -v colnum=$columnNumber -v require="$searchTerm"
"/$fileName/ { if (\$colnum == require) print }"
which works by setting awk variables (colnum and require, in this case) and then using the literal string $colnum to get the desired field, and the variable require to get the required-string.
Note that in all cases (with or without the grep command), any regular expression meta-characters in $fileName will be meta-y, e.g., this.that will match the file named this.that but also the file named thisXthat.

Resources