I have this ssh config that needs to be edited.
Host vps6
HostName 123.456.789.00
User dylan
Port 123
Host vps4
HostName 123.456.789.00
User dylan
Port 123
# old server
Host vps3-old
HostName 123.456.789.00
User dylan
Port 123
I want to move config for vps6
to end of file and append -old
to its config alias. The resulting file would be.
Host vps4
HostName 123.456.789.00
User dylan
Port 123
# old server
Host vps3-old
HostName 123.456.789.00
User dylan
Port 123
Host vps6-old
HostName 123.456.789.00
User dylan
Port 123
I managed to do exactly that using this sed command → sed '/'"vps4"'/{N;N;N;N;H;$!d}; ${p;x;s/'"vps4"'/'"vps4"'-old/}'
, unfortunately this gives me unwanted newline at the end of file.
[tmp]$ sed '/'"vps6"'/{N;N;N;N;H;$!d}; ${p;x;s/'"vps6"'/'"vps6"'-old/}' config
Host vps4
HostName 123.456.789.00
User dylan
Port 123
# old server
Host vps3-old
HostName 123.456.789.00
User dylan
Port 123
Host vps6-old
HostName 123.456.789.00
User dylan
Port 123
[tmp]$ # See above me
Moreover, I want to be able to specify the next n line to be moved (for example above will be mark Host vps4
and next 3 line to be moved to end of file). I have searched up the net and found out that the recommended tools for this kind of task is ed
, but I have yet to find out the example command to do exactly what I want.
CodePudding user response:
With your shown samples please try following awk
code.
awk '
!NF && found{
found=""
next
}
/^Host vps6/{
found=1
line=$0"-old"
next
}
found{
val=(val?val ORS:"")$0
next
}
!found
END{
print ORS line ORS val
}
' Input_file
NOTE: In case you want to save output into Input_file itself then run above program it will print output on terminal and once you are Happy with results of above program then you can append > temp && mv temp Input_file
to above program, to do inplace save into Input_file.
Explanation: Adding detailed explanation for above used code.
awk ' ##Starting awk program from here.
!NF && found{ ##Checking if line is empty AND found is SET then do following.
found="" ##Nullifying found here.
next ##next will skip all further statements from here.
}
/^Host vps6/{ ##If line starts from Host vps6 then do following.
found=1 ##Setting found here.
line=$0"-old"
next
}
found{ ##If found is set then do following.
val=(val?val ORS:"") $0 ##Creating val which is keep adding current line into it.
next ##next will skip all further statements from here.
}
!found ##If found is NOT set then print that line.
END{ ##Starting END block of this program from here.
print ORS line ORS val ##Printing ORS line ORS and val here.
}
' Input_file ##Mentioning Input_file name here.
CodePudding user response:
Another awk:
$ awk -v RS= '{ # read blank line separated records
if(/^Host vps6/) { # buffer matching record
sub(/vps6/,"vps6-old") # add -old
b=$0
} else # print non-matching
print $0 ORS # with with extra newline
}
END { # in the end
print b # output buffer
}' file
if [you] wanted to use variable instead of hardcoded string, use something like this:
$ awk -v s=vps6 -v RS= '{ # or -v s="$sshname"
if($0~"^Host " s) {
match($0,s)
b=substr($0,1,RSTART RLENGTH-1) "-old" substr($0,RSTART RLENGTH)
} else
print $0 ORS
}
END {
print b
}
CodePudding user response:
Edit: this is basically the same as @RavinderSingh13's answer, but not as good.
Another potential option:
cat file1
Host vps6
HostName 123.456.789.00
User dylan
Port 123
Host vps4
HostName 123.456.789.00
User dylan
Port 123
# old server
Host vps3-old
HostName 123.456.789.00
User dylan
Port 123
awk '
{flag=0}
/vps6/,/^$/ {flag=1}
{
gsub("vps6", "vps6-old")
if (flag == 0) print
if (flag == 1) a[NR]=$0
}
END {
print ""
for (i in a) {
if(a[i] != "") print a[i]
}
}' file1
Host vps4
HostName 123.456.789.00
User dylan
Port 123
# old server
Host vps3-old
HostName 123.456.789.00
User dylan
Port 123
Host vps6-old
HostName 123.456.789.00
User dylan
Port 123
CodePudding user response:
This might work for you (GNU sed):
sed '/Host vps6/{s//&-old/;:a;N;/\n$/!ba;H;d};$G' file
Match vps6
and append -old
.
Gather it up and the following lines until a spaced line, then copy those lines to the hold space (use H
rather than h
so as to prepend a newline).
Delete those lines.
At the end of the file append the copies.
If the empty line at the end of the file bothers you:
sed '/Host vps6/{s//&-old/;:a;N;s/\n$//;Ta;H;d};$G' file
CodePudding user response:
Here is a gnu-awk
solution that won't rely on extra line breaks between each Host
record:
awk -v RS='(^|\n)Host ' -v s='vps6' '
$1 == s {
sub(s, s "-old")
rec = RT $0
next
}
{ORS=RT}
1
END {print rec}' file
Host vps4
HostName 123.456.789.00
User dylan
Port 123
# old server
Host vps3-old
HostName 123.456.789.00
User dylan
Port 123
Host vps6-old
HostName 123.456.789.00
User dylan
Port 123