I have a bash script that needs to modify .ssh/config. My goal is to change the HostName value of server1 using sed and I have already managed to do it, but in the file there are more HostName and sed modifies them all. I have tried specifying to sed to stop at the first occurrence but continues to modify them all.
This is the file where I need to change the HostName of server1
Host server1
HostName 172.160.189.196
User admin
Port 353
Host server2
HostName 254.216.34.18
User user
Port 22
This is the command I give:
sed -i '0,/RE/s/HostName .*/HostName 14.208.54.132/' .ssh/config
Try using a sed range:
sed -i '/Host server1/,/HostName/ s/HostName .*/HostName 14.208.54.132/' .ssh/config
This will replace HostName in the range of lines between Host server1 and the first occurrence of HostName, which I think is what you want.
While awk is generally known to work on lines, it actually works with records, by default lines. A record can be defined by a record separator RS. If this variable is empty, it assumes that a record is given by text-blocks separated by one or more empty lines. With this you can do the following:
awk 'BEGIN{RS="";FS=OFS="\n";ORS="\n\n"}
($1~/server1/) {sub(/Hostname[^\n]*\n/,"Hostname 14.208.54.132" OFS)}
1' file
This is not short, but conceptually clean.
Obviously, you have to update the regex to match the hostname such that it is unique. If you also have a hostname server1a, then you will have to make sure that ($1~/server1/) does not match that.
You can use awk like this:
awk '$2=="server1" {f=1} f && /HostName/ {$0=" HostName 14.208.54.132";f=0} 1' file
Host server1
HostName 14.208.54.132
User admin
Port 353
Host server2
HostName 254.216.34.18
User user
Port 22
This might work for you (GNU sed):
sed '/\<server1\>/{:a;n;/HostName/!ba;s/\S\+/14.208.54.132/2}' file
Focus on a line containing server1 then read additional lines until one containing HostName and substitute the second field for the desired result.
Related
I want to edit content of pg_hba.conf using sed :
# "local" is for Unix domain socket connections only
local all all peer
to
# "local" is for Unix domain socket connections only
local all all trust
For know, I use this command that works:
sed -i 's/local all all peer/local all all trust/' pg_hba.conf
But I'm looking for a way to bypass all theses spaces
You can use
sed -E -i 's/local([[:space:]]+)all([[:space:]]+)all([[:space:]]+)peer/local\1all\2all\3trust/' test.conf
Or, since it seems like you have a GNU sed:
sed -E -i 's/local(\s+)all(\s+)all(\s+)peer/local\1all\2all\3trust/' test.conf
And certainly you can do as potong did in the comments and reduce this to
sed -E -i 's/(local\s+all\s+all\s+)peer/\1trust/' test.conf
Note:
-E enables the POSIX ERE syntax (no need to escape + and (...))
([[:space:]]+) / (\s+) defines capturing groups with IDs starting with 1 that match one or more whitespaces
\1, \2 and \3 are placeholders, backreferences to the appropriate group values.
In s/(local\s+all\s+all\s+)peer/\1trust/, you capture the whole part before peer and match peer, then the whole match is replaced with the part before peer (with \1) + trust.
You could use this sed if the string that needs to be changed is not always going to be peer
$ sed -i 's/\S*$/trust/' input_file
# local is for Unix domain socket connections trust
local all all trust
The file /var/cpanel/mainip contains the main IP of my server and nothing else.
The file /etc/csf/csf.blocklists contains a list of firewall blocklists, and part of the file contains a line with an example IP address 1.2.3.4
Normally when installing CSF firewall software on a new server, I will manually replace the example IP address with the server's main IP address. This is required to successfully fetch firewall blocklists from some providers.
To simplify the setup process, I want a command that will replace the example IP address 1.2.3.4 with my main server IP so I don't have to manually do it.
I've tried a sed command, I guess I'm close to the correct command but not quite there yet. Please can you help?
sed -i '/1.2.3.4/ { r /etc/csf/csf.blocklists }' /var/cpanel/mainip
This code is not right because it outputs an error:
sed: -e expression #1, char 0: unmatched `{'
When successful, it should replace 1.2.3.4 with the actual server IP address.
sed -i "s/1\.2\.3\.4/$(</var/cpanel/mainip)/" /etc/csf/csf.blocklists
should do the job.
You only need to specify
sed -i '/1.2.3.4/r /etc/csf/csf.blocklists' /var/cpanel/mainip
In fact even the space is optional ; following will work too
sed -i '/1.2.3.4/r/etc/csf/csf.blocklists' /var/cpanel/mainip
You are simply specifying the pattern /1.2.3.4/ and a command after that
The command could be r for read, w for write, d for delete and a few others
An example of d to delete the entry would be
sed -i '/1.2.3.4/d' /var/cpanel/mainip
I have a host file with the below lines:
127.0.0.1
127.0.1.1 servername
The server IP is : 192.168.1.1 which is represented by the IP variable below:
IP=192.168.1.1
I want to replace the second entry that starts with 127.0 with $IP i.e:
instead of :
127.0.1.1 servername
it should be :
192.168.1.1 servername
I tried to use the below sed statement :
sed "0,/127.0.*/! s/127.0.*/$IP/" /etc/hosts
But its replacing the entire line removing the servername as well ,and leave me with :
127.0.0.1 localhost.localdomain localhost
192.168.1.1
its should be :
192.168.1.1 servername
. is a regex-active character, you need to escape it with a backslash (\),
.* will match everything until EOL, use a negated character class for matching everything until first blank character instead.
sed '0,/^127\.0\./! s/^127\.0\.[^[:blank:]]*/'"$IP"'/' file
Btw, you could get this task done way more safely&robustly using awk:
$ awk -v IP="$IP" 'n<2 && index($1,"127.0.")==1 && ++n==2 { $1=IP } 1' file
127.0.0.1
192.168.1.1 servername
We have a large log file in the same location on multiple servers and I want to create a cron job to truncate the file to last 100k lines.
The following command works:
sed -i 1,$(($(wc -l < /root/server123.example.com.log) -100000))d /root/server123.example.com.log
But the hostname on each server is different (server1, server2, server3 etc.), and I'd like to have a single command I can paste into each cron file. During my testing I wasn't sure how to achieve a wildcard in the above command.
I think the best way might be to combine it with a find command, but I'm clueless on how to do that..
find /root/server*.example.com.log -type f -exec sed <NOT SURE..> \;
Any help would be appreciated.
During my testing I wasn't sure how to achieve a wildcard in the above command.
If there is just one log file on each server, you can simply insert the wildcard:
sed -i 1,$(($(wc -l < /root/server*.example.com.log) -100000))d /root/server*.example.com.log
I have the following line in my proftpd log (line 78 to be precise)
Deny from 1.2.3.4
I also have a script which rolls through my logs for people using brute force attacks and then stores their IP (ready for a black listing). What i'm struggling with is inserting (presume with sed) at the end of that specific line - this is what I've got so far:
sed "77i3.4.5.6" /opt/etc/proftpd.conf >> /opt/etc/proftpd.conf
Now one would presume this would work perfectly, however it actually does the following (lines 77 through 78):
3.4.5.6
Deny from 1.2.3.4
I suspect this is due to my dated version of sed, are there any other ways of acheiving the same thing? Also the >> causes the config to be duplicated at the end of the fole (again i'm sure this is a limitation of my version of sed). This is running a homebrew linux kernel on my nas. Sed options below:
root#NAS:~# sed BusyBox v1.7.0
(2009-04-29 19:12:57 JST) multi-call
binary
Usage: sed [-efinr] pattern [files...]
Options:
-e script Add the script to the commands to be executed
-f scriptfile Add script-file contents to the
commands to be executed
-i Edit files in-place
-n Suppress automatic printing of pattern space
-r Use extended regular expression syntax
If no -e or -f is given, the first
non-option argument is taken as the
sed script to interpret. All remaining
arguments are names of input files; if
no input files are specified, then the
standard input is read. Source files
will not be modified unless -i option
is given.
Cheers for your help guys.
This has nothing to do with the version of sed; this is just plain old Doing It Wrong.
sed -i '77s/$/,3.4.5.6/' /opt/etc/proftpd.conf