ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I have a current code working(named subst1) having a user be able to type this line to substitute words using the sed command:
Code:
subst1 old-pattern new-pattern filename
Here is my shell script:
Code:
#!/bin/bash
# subst1
ARGS=3
E_BADARGS=65
if [ $# -ne "$ARGS" ]
then
echo "Usage: `basename $0` old-pattern new-pattern filename"
exit $E_BADARGS
fi
old_pattern=$1
new_pattern=$2
if [ -f "$3" ]
then
file_name=$3
else
echo "File \"$3\" does not exist."
exit $E_BADARGS
fi
mv $file_name $file_name.bak
sed -e "s/$old_pattern/$new_pattern/g" $file_name.bak > $file_name
exit 0
The problem with this script is that it changes the date and creates a bak file. I need to alter this script so that when a user inputs the command line, the script checks if the given old-pattern is in the file and if it is, go ahead and do the substitution and create the bak file. If the old-pattern is not found, the script should do nothing. Any help would be appreciated!
You can previously look for the pattern using grep. The last part of the script could be:
Code:
if [ -f "$3" ]
then
file_name=$3
else
echo "File \"$3\" does not exist."
exit $E_BADARGS
fi
if grep -q $old_pattern $file_name
then
mv $file_name $file_name.bak
sed -e "s/$old_pattern/$new_pattern/g" $file_name.bak > $file_name
else
echo "Pattern $old_pattern not found in $file_name"
echo "Nothing to do, here!
fi
Also consider the -i option of sed to edit the file in place: once you've safely created the backup file, you can simply do
Code:
cp -p $file_name $file_name.bak
sed -i "s/$old_pattern/$new_pattern/g" $file_name
Thank you so much for this! I knew it was an easy grep command but I couldn't seem to get why it was working. If you could help with just one more thing, I would love you for the rest of my life haha. I need to use this script and alter it so that it lets you change ANY number of files at once by just typing:
count=3
while [ $count -le $# ]
do
eval sed -i "s/$1/$2/g" \$$count
((count++))
done
The eval before the sed command permits indirect reference to the positional parameter: $3, $4, $5 and so on... where 3, 4, 5... is the value of the variable count. Your script will become something like (again the last part only)
Code:
count=3
while [ $count -le $# ]
doeval file_name=\$$count
if [ ! -f "$file_name" ]
then
echo "File \"$file_name\" does not exist."
exit $E_BADARGS
fi
if grep -q $old_pattern $file_name
then
cp -p $file_name $file_name.bak
sed -i "s/$old_pattern/$new_pattern/g" $file_name
else
echo "Pattern $old_pattern not found in $file_name"
fi
((count++))done
Just out of curiosity: why do you need to wrap the sed substitution in a shell script? Can't you instruct the users to do a sed command? It permits editing of multiple files as well:
Code:
sed -i 's/old_pattern/new_pattern/g' file1 file2 file3 file4 file5
When I tried this...I just get the output statement saying the way to use the shell script. This is what I see when testing it:
Code:
Usage: subst old-pattern new-pattern filename
Here is the code:
Code:
#!/bin/bash
# subst
ARGS=3
E_BADARGS=65
if [ $# -ne "$ARGS" ]
then
echo "Usage: `basename $0` old-pattern new-pattern filename"
exit $E_BADARGS
fi
old_pattern=$1
new_pattern=$2
if [ -f "$3" ]
then
file_name=$3
else
echo "File \"$3\" does not exist."
exit $E_BADARGS
fi
count=3
while [ $count -le $# ]
do
eval file_name=\$$count
if [ ! -f "$file_name" ]
then
echo "File \"$file_name\" does not exist."
exit $E_BADARGS
fi
if grep -q $old_pattern $file_name
then
mv $file_name $file_name.bak
sed -e "s/$old_pattern/$new_pattern/g" $file_name.bak > $file_name
else
echo "String \"$1\" does not exist."
exit $E_BADARGS
fi
((count++))
done
Just out of curiosity: why do you need to wrap the sed substitution in a shell script? Can't you instruct the users to do a sed command? It permits editing of multiple files as well:
Code:
sed -i 's/old_pattern/new_pattern/g' file1 file2 file3 file4 file5
I know it would just be easier to have the users do the sed command but my colleague thinks that this command is used so often that it should be written into a shell script. bleh
When I tried this...I just get the output statement saying the way to use the shell script.
You have to strip out the check for 3 arguments if you want an unlimited number of them.
Quote:
Originally Posted by Todd88
also -i option for sed is invalid
The -i option is for GNU sed only. Are you running on Solaris or something? Anyway, you can stick with your original version, editing the backup file and redirecting output to the original file name.
It's generally easier to use a for loop rather than counting the command line arguments manually,
Code:
for file in $@; do
...
done
You'll need a
Code:
shift 2
after you assign the old/new patterns from $1 and $2, this will eat the patterns so all remaining arguments are filenames.
Also, it's a good idea to quote variables since most shells are retarded and will split them automatically if they contain whitespace.
Lastly, instead of exiting if a file or pattern doesn't exist, it would be better to continue after printing the error message (might be irritating if a user specified 200 files and the script exits at file #3 because of a typo).
Code:
#!/bin/bash
# subst
E_BADARGS=65
# need 2 patterns and at least 1 filename
if [ $# -lt 3 ]
then
echo "Usage: `basename $0` old-pattern new-pattern filename [filename...]"
exit $E_BADARGS
fi
old_pattern="$1"
new_pattern="$2"
shift 2
for file_name in "$@"; do
if [ ! -f "$file_name" ]
then
echo "File \"$file_name\" does not exist."
continue
fi
if grep -q "$old_pattern" "$file_name"
then
mv "$file_name" "${file_name}.bak"
sed -e "s/$old_pattern/$new_pattern/g" "${file_name}.bak" > "$file_name"
else
echo "String \"$1\" does not exist in $filename."
fi
done
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.