Need help with scripting mass file edits..

Hello,

I am wanting to know a way to shell (ksh)script-edit a file by having a script that searches for a specific string, and then input lines of text in the file after that specific string. Please help, as I will be up all night if I can't figure this out.

You could do it by using read to read each line, grep to search for the string

eg

while read N
do
       echo "$N" | grep $STRING
       if test "$?" = "0"
       then
             echo new line
             echo new line
       fi
       echo $N
done

You can also try sed

place all the replace instances in a file ( sed_file) with entries
s/[search string1]/[replace string1]/g
s/[search string2]/[replace string2]/g

Then to make the replacements do as :

$ sed -f sed_file [input file]

Perhaps I should have stated that I wanted to input lines of text after the string that is being searched out. I have to do this on 398 servers tonight. Please help!

while read N
do
       echo "$N" | grep $STRING
       if test "$?" = "0"
       then
             echo $N
             echo new line
             echo new line
       else
            echo $N
       fi
done

How did you end up with this job?

LOL! Long story...

Thanks for the responses everyone. It was a last minute thing my mngr gave me. I have to add lines to the sudoers file on 398 servers, and I want to keep the file tidy, and not just append everything to the end.

What's the problem with the SED script. can u give a small example for the illustration of the problem.

Abhi.

I don't know enough about SED to know if there is a problem with the SED script.

One example of what I am trying to do is as follows:

Let say I wanted to add a user alias line to the sudoers file such as:

User_Alias SOME_ADMINS = user1

At the start of that section of the file, is the heading that tells what section it is:

# User alias specification

I would want to search for this headding, and add the user alias line after that, while not deleting anything else in the file.

Someone gave me this perl solution:

perl -pi.old -e 's/(localhost)(.*)/$1\n$2\nnew\nlines\nhere/' file1 file2 file3

What this example does is search for the string 'localhost', moves the existing text on the line after the string down a line, and inserts the new lines. It does this for 3 files( file1, file2, and file3). I tested this out like so:

perl -pi.old -e 's/(#Section 2)(.*)/$1\n$2\It Worked!!!/' file1

This was the result I found when I looked at file1:

Before:

#Section 1
This is some stuff I am typing in this file for space.

#Section 2

After (I did it several times):

#Section 1
This is some stuff I am typing in this file for space.

#Section 2
It Worked!!!
It Worked!!!
It Worked!!!
It Worked!!!
It Worked!!!

The problem comes when I try to enter this:

Cmnd_Alias EPROV_ADMIN_CMDS = /usr/sbin/groupadd, /usr/sbin/groupdel, /usr/sbin/groupmod, \
/usr/bin/last, /usr/bin/listusers, /usr/sbin/logins, \
/usr/sbin/usermod, /usr/sbin/useradd, /usr/sbin/userdel, \
/usr/bin/passwd, /usr/bin/ypmatch, /usr/bin/yppasswd, \
/usr/sbin/ypcat, /usr/bin/login

What would be the best way to enter this? In other words, I need to be able to enter absolute paths to files.

As I stated above, it may not be the best approach. 'sed' searches for [search string] and replaces it with [replace string]

As per your requirement, you want the search string as well as the replaced string on the next line.

Note: if you have many replacements in a file make a temp file [sed_file] and input in it the following entries --
s/[search string1]/"[search string1] \n [replace string1]"/g
s/[search string2]/"[search string2] \n [replace string2]"/g

save this file and to make the global replacement in any file (input_file) run the following command -

sed -f sed_file input_file.

The sed command here will look for replacements from sed_file and make proper changes in the input_file.
Let me know if this helps.

Abhi.

1 Like
change="User_Alias SOME_ADMINS = user1"
awk -v c="$change" '{print}
/User alias specification/{print c}
' "file" > temp
mv temp file
1 Like

But will this work with the list of absolute path names above? Please help!!

Thanks, I'll give this a try.

This has been working great. I found out that the awk argument can't take more than 399 bytes. About to find out how scalable it is.

How would I run this remotely with ssh on multiple servers?

Ended up pushing the file out to all the servers, and running a remote ssh to execute them. Worked like a charm. I was more comfortable using Ghostdog74's method, and adapting it to fit my needs. Here is the way I did it below. You just have to make sure all your sudoers files are uniform across your environment first:

Here's how I pushed the files out to the servers:

NOTE: This is assuming you have your ssh key from your jump server distributed to the rest of the hosts, so you don't have to use a password to login.

#!/bin/ksh

for i in `serverlist.txt`
do
echo $i
ssh $i "/etc/change_sudo.sh"
echo
done > change_sudo.output

change_sudo.sh

#!/bin/ksh

cd /etc
cp sudoers sudoers.safe

change0="Host_Alias LOCALHOST = `hostname`"
awk -v c="$change0" '{print}
/# Host alias specification/{print c}
' "sudoers" > temp.sudoers
mv temp.sudoers sudoers
chown root:root sudoers
chmod 440 sudoers

change1="User_Alias  ADMINS = someuser"
awk -v c="$change1" '{print}
/# User alias specification/{print c}
' "sudoers" > temp.sudoers
mv temp.sudoers sudoers
chown root:root sudoers
chmod 440 sudoers

sleep 02

change2="Cmnd_Alias MISC_CMDS =  /usr/bin/make, /usr/bin/chmod, /usr/bin/awk, /usr/bin/cat,/usr/bin/chown, /usr/bin/cp, /usr/bin/cut, /usr/bin/diff,/usr/bin/grep, /usr/bin/ls, /usr/bin/mv, /usr/bin/rm,/usr/bin/sed, /usr/bin/sleep, /usr/bin/sort, /usr/bin/tail,/bin/echo, /bin/touch, /usr/bin/which"
awk -v c="$change2" '{print}
/# Cmnd alias specification/{print c}
' "sudoers" > temp.sudoers
mv temp.sudoers sudoers
chown root:root sudoers
chmod 440 sudoers

sleep 02

change3="Cmnd_Alias PROTECTED_CMDS = !/usr/bin/passwd root, !/usr/bin/rm -rf /*, !/usr/bin/chown root"
awk -v c="$change3" '{print}
/# Cmnd alias specification/{print c}
' "sudoers" > temp.sudoers
mv temp.sudoers sudoers
chown root:root sudoers
chmod 440 sudoers

sleep 02

change4="Cmnd_Alias ADMN_CMDS = /usr/sbin/groupadd, /usr/sbin/groupdel, /usr/sbin/groupmod, /usr/bin/last, /usr/bin/listusers, /usr/sbin/logins, /usr/sbin/usermod, /usr/sbin/useradd, /usr/sbin/userdel, /usr/bin/passwd, /usr/bin/ypmatch, /usr/bin/yppasswd,/usr/sbin/ypcat, /usr/bin/login"
awk -v c="$change4" '{print}
/# Cmnd alias specification/{print c}
' "sudoers" > temp.sudoers
mv temp.sudoers sudoers
chown root:root sudoers
chmod 440 sudoers

sleep 02

change5="ADMINS  LOCALHOST = MISC_CMDS,ADMIN_CMDS"
awk -v c="$change5" '{print}
/# User privilege specification/{print c}
' "sudoers" > temp.sudoers
mv temp.sudoers sudoers
chown root:root sudoers
chmod 440 sudoers

And here was the result:

Sudoers File Before:

#Host alias specification

# User alias specification

#Cmnd alias specification

# User privilege specification

Sudoers File After:

#Host alias specification
Host_Alias LOCALHOST = servername

# User alias specification
User_Alias ADMINS = someuser

#Cmnd alias specification

Cmnd_Alias ADMIN_CMDS = /usr/sbin/groupadd, /usr/sbin/groupdel, /usr/sbin/groupmod, /usr/bin/last, /usr/bin/listusers, /usr/sbin/logins, /usr/sbin/usermod, /usr/sbin/useradd, /usr/sbin/userdel, /usr/bin/passwd, /usr/bin/ypmatch, /usr/bin/yppasswd,/usr/sbin/ypcat, /usr/bin/login
Cmnd_Alias PROTECTED_CMDS = !/usr/bin/passwd root, !/usr/bin/rm -rf /*, !/usr/bin/chown root
Cmnd_Alias MISC_CMDS = /usr/bin/make, /usr/bin/chmod, /usr/bin/awk, /usr/bin/cat,/usr/bin/chown, /usr/bin/cp, /usr/bin/cut, /usr/bin/diff,/usr/bin/grep, /usr/bin/ls, /usr/bin/mv, /usr/bin/rm,/usr/bin/sed, /usr/bin/sleep, /usr/bin/sort, /usr/bin/tail,/bin/echo, /bin/touch, /usr/bin/which

# User privilege specification
ADMINS LOCALHOST = MISC_CMDS,ADMIN_CMDS

Excellent.

Thanks for posting your solution back for the benefit of others.