Match a string, skip if it has a . (DOT) infront of the result - sed

Here's what I use to match a string in a variable and delete the line where the match exists:
sed -i '/'"$domainAndSuffix.cfg"'/d' /etc/file
I'd like to know how to match a string in a variable, but if the match in the file has a . adjacent to it on the immediate left, then it will NOT delete this line and keep going through the file until it finds a match without a .
Sample file Contents:
happy.domain.com
pappy.domain.com
domain.com
String to match:
domain.com
Desired File Output:
happy.domain.com
pappy.domain.com
*Edit:
Actual File Contents:
cfg_file=/etc/nagios/objects/http_url/bob.ca.cfg
cfg_file=/etc/nagios/objects/http_url/therecord.com.cfg
cfg_file=/etc/nagios/objects/http_url/events.therecord.com.cfg
cfg_file=/etc/nagios/objects/http_url/read.therecord.com.cfg
cfg_file=/etc/nagios/objects/http_url/wheels.ca.cfg
cfg_file=/etc/nagios/objects/http_url/used-vehicle-search.autos.ca.msn.com.cfg
cfg_file=/etc/nagios/objects/http_url/womensweekendshow.com.cfg
cfg_file=/etc/nagios/objects/http_url/yorkregion.com.cfg
cfg_file=/etc/nagios/objects/http_url/yourclassifieds.ca.cfg

If the preceding substring is fixed, you can try the following:
PREFIX='cfg_file=\/etc\/nagios\/objects\/http_url\/'
DOMAIN='therecord.com'
sed -i "/^${PREFIX}${DOMAIN}/d" file
If it is not fixed, it would be nice to use a negative lookbehind, but sed can't do that. You can use ssed or GNU grep:
ssed -Ri '/(?<!\.)'"$DOMAIN"'.cfg/d' file
or
grep -vP '(?<!\.)'"$DOMAIN" > file1; mv file1 file

Related

how should I use system command in perl

I want to replace a line with the $var.
runnew has
input= input/old/should/change;
replace= input/old/replace;
other = input/old/other;
replace_other= input/old/replace_other;
My output file should look like,
input= input/old/should/New;
replace= input/old/New_replace;
other = input/old/New_other;
replace_other= input/old/New_replace_other;
I want to replace "input =" by input = input/old/should/New;
I have used like,
if ($#ARGV != 0) {
die "\n********USAGE <cellname> <tech>********\n";
}
$newinput=$ARGV[0];
open(my $fh, "$runnew") or die "Could not open rerun.txt: $!";
while (<$fh>) {
system ( sed -i "/input=.*/c\input= $newinput" $runnew );
}
But there is error popping up "Scalar found where operator expected at run.pl" and its displaying sed line and asking " (Missing operator before $runnew?)."
When I used same sed on terminal its replacing the line .
Please can anyone point out where the error is ?
Yes Using Sed is simple but I have file with different lines and each line should be replaced .
Please let me knoe if you have better idea than this.
Thanks in advance.
system() takes a list of strings as its argument. You you need to put quotes around the command you pass it.
system ( "sed -i '/input=.*/c\input= $newinput' $runnew" );
But your code still looks very strange. You're running exactly the same sed command for every line in the input file. Is that what you meant to do?
It's not really clear what you're trying to do here. But I'm confident that the best approach would involve not using sed and using Perl to make your transformations.
Why do you want to call sed at all? Your requirement can be much easier handled in Perl directly:
add -i.bak to enable in-place replacement mode
use the first command line parameter as replacement string
remove it from the #ARGV array so it will not be interpreted as file
loop over all files on the command line
read line by line
apply substitution
print result
Perl automatically takes care of opening the files, writing to the correct file and renaming old files to .bak.
#!/usr/bin/perl -i.bak
use warnings;
use strict;
my($replacement) = shift(#ARGV);
while (<>) {
s/input=.*/input= $replacement/;
print;
}
exit 0;
Test run (taking an educated guess on your input data):
$ cat dummy1.txt.bak
input= test1
input= test2
$ cat dummy2.txt.bak
input= test3
input= test4
$ perl dummy.pl REPLACEMENT dummy1.txt dummy2.txt
$ cat dummy1.txt
input= REPLACEMENT
input= REPLACEMENT
$ cat dummy2.txt
input= REPLACEMENT
input= REPLACEMENT
or to use the contents of the file "rerun.txt":
$ perl dummy.pl REPLACEMENT $(cat rerun.txt)

how to replace with sed when source contains $

I have a file that contains:
$conf['minified_version'] = 100;
I want to increment that 100 with sed, so I have this:
sed -r 's/(.*minified_version.*)([0-9]+)(.*)/echo "\1$((\2+1))\3"/ge'
The problem is that this strips the $conf from the original, along with any indentation spacing. What I have been able to figure out is that it's because it's trying to run:
echo " $conf['minified_version'] = $((100+1));"
so of course it's trying to replace the $conf with a variable which has no value.
Here is an awk version:
$ awk '/minified_version/{$3+=1} 1' file
$conf['minified_version'] = 101
This looks for lines that contain minified_version. Anytime such a line is found the third field, $3, is incremented by.
My suggested approach to this would be to have a file on-disk that contained nothing but the minified_version number. Then, incrementing that number would be as simple as:
minified_version=$(< minified_version)
printf '%s\n' "$(( minified_version + 1 ))" >minified_version
...and you could just put a sigil in your source file where that needs to be replaced. Let's say you have a file named foo.conf.in that contains:
$conf['minified_version'] = #MINIFIED_VERSION#
...then you could simply run, in your build process:
sed -e "s/#MINIFIED_VERSION#/$(<minified_version)/g" <foo.conf.in >foo.conf
This has the advantage that you never have code changing foo.conf.in, so you don't need to worry about bugs overwriting the file's contents. It also means that if you're checking your files into source control, so long as you only check in foo.conf.in and not foo.conf you avoid potential merge conflicts due to context near the version number changing.
Now, if you did want to do the native operation in-place, here's a somewhat overdesigned approach written in pure native bash (reading from infile and writing to outfile; just rename outfile back over infile when successful to make this an in-place replacement):
target='$conf['"'"'minified_version'"'"'] = '
suffix=';'
while IFS= read -r line; do
if [[ $line = "$target"* ]]; then
value=${line##*=}
value=${value%$suffix}
new_value=$(( value + 1 ))
printf '%s\n' "${target}${new_value}${suffix}"
else
printf '%s\n' "$line"
fi
done <infile >outfile

Replace period with dash via command line?

Here's my current command:
sed 's/\./-/' file.txt > CLEANED.txt
What I'm trying to do is replace all periods in my file with a dash. Some lines have multiple periods and I need all of them replaced with a dash - but the command above seems to just replace the first one in each line.
What am I doing wrong for it to not replace all of the periods?
In perl, just add the /g modifier to your regex:
perl -pe 's/\./-/g' file.txt > CLEANED.txt
Explanation:
Switches:
-p: Creates a while(<>){...; print} loop for each “line” in your input file.
-e: Tells perl to execute the code on command line.
Code:
s/\./-/g: Replace all periods with dashes. Could also use the transliteration operator: y/./-/
Add /g for a global replacement, else it only affects the first occurrence.
Like so:
sed 's/\./-/g' file.txt > CLEANED.txt

Best way to parse this particular string using awk / sed?

I need to get a particular version string from a file (call it version.lst) and use it to compare another in a shell script. For example sake, the file contains lines that look like this:
V1.000 -- build date and other info here -- APP1
V1.000 -- build date and other info here -- APP2
V1.500 -- build date and other info here -- APP3
.. and so on. Let's say I am trying to grab the first version (in this case, V1.000) from APP1. Obviously, the versions can change and I want this to be dynamic. What I have right now works:
var = `cat version.lst | grep " -- APP1" | grep -Eo V[0-9].[0-9]{3}`
Pipe to grep will get the line containing APP1 and the second pipe to grep will get the version string. However, I hear grep is not the way to do this so I'd like to learn the best way using awk or sed. Any ideas? I am new to both and haven't found a tutorial easy enough to learn the syntax of it. Do they support egrep? Thanks!
Try this to get the complete version:
#!/bin/sh
app=APP1
var=$(awk -v "app=$app" '$NF == app {print $1}' version.lst)
or to get only the major version number, the last line could be:
var=$(awk -v "app=$app" '$NF == app {split($1,a,"."); print a[1]}' version.lst)
Using sed to get the complete version:
var=$(sed -n "/ $app\$/s/^\([^ ]*\).*/\1/p" version.lst)
or this to get only the major version number:
var=$(sed -n "/ $app\$/s/^\([^.]*\).*/\1/p" version.lst)
Explanations:
The second AWK command:
-v "app=$app" - set an AWK variable equal to a shell variable
$NF == app - if the last field is equal to the contents of the variable (NF is the number of field, so $NF is the contents of the NFth field)
{split($1,a,".") - then split the first field at the dot
print a[1] - and print the first part of the result of the split
The sed commands:
-n - don't print any output unless directed to
"/ $app\$/ - for any line that ends with (\$) the contents of the shell variable $app (not that double quotes are used to allow the variable to be expanded and it's a good idea to escape the second dollar sign)
s/^\([^ ]*\).*/\1/p" - starting at the beginning of the line (^), capture \(\) the sequence of characters that consists of non-spaces ([^ ]) (or non-dots in the second version) of any number (zero or more *) and match but don't capture all the rest of the characters on the line (.*), replace the matched text (the whole line in this case) with the string that was captured (the version number) (\1 refers to the first (only, in this case) capture group, and print it (p)
If I understood correctly: egrep "APP1$" version.lst | awk '{print $1}'
$ awk '/^V1\.00.* APP1$/{print $NF}' version.lst
APP1
That regular expression matches lines that start with "V1.00", followed by any number of any other characters, ending with " APP1". The backslash in the middle there might be really important--it matches only ".", and so it excludes (probably corrupt) lines that might begin with, say, "V1a00". The space before "APP1" excludes things like "APP2_APP1".
"NF" is an automatically generated variable that contains the number of field in the input line. It's also the number of the last field, which happens to be the one you're interested in.
There are a couple of ways to prune off the "V1". Here's one way, although you and I might not be talking about quite the same thing.
$ awk '/^V1\.00.* APP1$/{print substr($1, 1, index($1, ".") - 1), $NF}' version.lst
V1 APP1

replace line with sed in csh

I am trying to change the content of a specific line in a batch of files. I thought that would be a piece of cake but for some reason, nothing happens, so I guess I am missing something.
Line 8 should have been replaced.
Here the csh script I used:
#!/bin/csh
#
# replace context in line xxx by yyy
# 2010/05/07
set files = `ls FILENAMEPART*`
echo $files
foreach file ($files)
sed '8,8 s/1/2 /' $file
end
thanks for suggestions
sed prints the resulting file (with the lines replaced) to stdout by default and leaves the source (input) file untouched. Use the -i option for in-place editing, which means that the changes are made directly in $file.