LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-05-2008, 10:49 AM   #1
Todd88
LQ Newbie
 
Registered: Jul 2008
Posts: 6

Rep: Reputation: 0
Simple shell script - sed command


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!
 
Old 07-05-2008, 11:00 AM   #2
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
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
 
Old 07-05-2008, 11:17 AM   #3
Todd88
LQ Newbie
 
Registered: Jul 2008
Posts: 6

Original Poster
Rep: Reputation: 0
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:

Code:
subst1 old-pattern new-pattern file file file file
where file can be any file and number of times.
 
Old 07-05-2008, 11:52 AM   #4
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
In short, you can do something like this:
Code:
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 $# ]
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
    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
Quote:
I would love you for the rest of my life
Never mind. Save your love for a beautiful girl!
 
Old 07-05-2008, 12:00 PM   #5
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
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
 
Old 07-05-2008, 12:17 PM   #6
Todd88
LQ Newbie
 
Registered: Jul 2008
Posts: 6

Original Poster
Rep: Reputation: 0
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
 
Old 07-05-2008, 12:18 PM   #7
Todd88
LQ Newbie
 
Registered: Jul 2008
Posts: 6

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by colucix View Post
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
 
Old 07-05-2008, 12:30 PM   #8
Todd88
LQ Newbie
 
Registered: Jul 2008
Posts: 6

Original Poster
Rep: Reputation: 0
also -i option for sed is invalid
 
Old 07-05-2008, 12:46 PM   #9
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Quote:
Originally Posted by Todd88 View Post
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 View Post
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.
 
Old 07-05-2008, 12:53 PM   #10
Todd88
LQ Newbie
 
Registered: Jul 2008
Posts: 6

Original Poster
Rep: Reputation: 0
ah geez. Of course, thanks again. You saved me!
 
Old 07-06-2008, 04:33 PM   #11
smoked kipper
Member
 
Registered: May 2008
Location: UK
Distribution: Slackware,Slamd64
Posts: 81

Rep: Reputation: 15
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
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Shell Script , using Sed mogra Linux - Newbie 8 05-07-2008 01:18 PM
sed and awk in shell script bondoq Linux - Newbie 14 07-27-2007 01:52 AM
Using sed in a shell script RobHill Linux - General 4 05-29-2007 03:31 PM
Can't seem to run a simple shell script error command not found each time SimonT Linux - Newbie 5 10-29-2006 06:31 AM
shell command help, sed i think infamous41md Programming 2 08-15-2004 02:55 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:08 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration