Need help integrating a perl command into a shell script.

D

Daryl Rose

I need to edit 100 or more shell scripts. These shell scripts have
been moved, and they have a single line in them that define a specific
path. i.e. FILEDIR="/opt/<subdir>/file"

This path needs to be changed. The opt directory is the only
consistent within this path. The name of the subdir, and the file
name change.

I do almost all of my work in shell, I rarely ever use PERL, but I
feel perl would be the best solution for this purpose. I know that I
can use the substitute operator to change this line without a bunch of
messy redirects and move commands to rename the files.

The way that I was planning on doing this was something like:

find . -exec grep -l <string here> {} ;/ |while read line
do

var1=`echo $line |awk -F"/" '{print $3}'` # get the subdir name.
var2=`echo $line |awk -F"/" '{print $4}'` # get the file name.

perl -ip -e 's/SEARCH/REPLACE/' $var1/$var2

done


The problem that I am having is the SEARCH and REPLACE strings. Since
the subdir and file name are going to change within each file, I'm not
sure how to pass the variables into the substitute command. Could one
of you perl experts give me a suggestion on how to do this?

Thank you.

Daryl Rose
 
R

RedGrittyBrick

Daryl said:
I need to edit 100 or more shell scripts. These shell scripts have
been moved, and they have a single line in them that define a specific
path. i.e. FILEDIR="/opt/<subdir>/file"

This path needs to be changed. The opt directory is the only
consistent within this path. The name of the subdir, and the file
name change.

I do almost all of my work in shell, I rarely ever use PERL, but I
feel perl would be the best solution for this purpose. I know that I
can use the substitute operator to change this line without a bunch of
messy redirects and move commands to rename the files.

The way that I was planning on doing this was something like:

find . -exec grep -l <string here> {} ;/ |while read line
do

var1=`echo $line |awk -F"/" '{print $3}'` # get the subdir name.
var2=`echo $line |awk -F"/" '{print $4}'` # get the file name.

perl -ip -e 's/SEARCH/REPLACE/' $var1/$var2

done

You should be able to arrange for the shell to interpolate $var1 and
$var2 into the perl program:

perl -i -p -e "s(/opt/\w+/\w+)(/opt/$var1/$var2)" $var1/$var2

(note the use of double quotes)

However the overall task may be more easily accomplished using Perl's
FileFind module.
 
B

Ben Morrow

Quoth Daryl Rose said:
I need to edit 100 or more shell scripts. These shell scripts have
been moved, and they have a single line in them that define a specific
path. i.e. FILEDIR="/opt/<subdir>/file"

This path needs to be changed. The opt directory is the only
consistent within this path. The name of the subdir, and the file
name change.

You haven't said what you want to change it to. I'm assuming you want to
I do almost all of my work in shell, I rarely ever use PERL,

Perl, or perl: it's not a acronym. Some people here get quite upset when
people get it wrong. :)
but I
feel perl would be the best solution for this purpose. I know that I
can use the substitute operator to change this line without a bunch of
messy redirects and move commands to rename the files.

FWIW you can do the same with sed (perl's -i option is inherited from
sed). I'd rather use Perl, because I hate POSIX regular expression
syntax, but using sed is more shellish.
The way that I was planning on doing this was something like:

find . -exec grep -l <string here> {} ;/ |while read line

You need to learn about xargs. find without xargs is practically
useless. Something like

find . | xargs grep -l <string> | xargs sed -i -Ee'...'

(-r instead of -E for GNU sed, or omit if you can stand BREs :) ).
do

var1=`echo $line |awk -F"/" '{print $3}'` # get the subdir name.
var2=`echo $line |awk -F"/" '{print $4}'` # get the file name.

perl -ip -e 's/SEARCH/REPLACE/' $var1/$var2

done

I would use something more like (untested)

find . -type f | xargs perl -0377 -pi -e'/<string here>/ and
s,(FILEDIR)="/opt/ ([^/]+) / ([^"]+) ",$1="/new/$2/$3",gx'

(actually I'd probably do the whole thing in Perl, using
File::Find::Rule, but this is a more shellish solution). The -0377 says
to read the whole file in one go, which allows you to omit the grep
altogether while still using perl -p. The /x modifier on the s,,, allows
whitespace in the first section, which makes it at least slightly
comprehensible :).

Ben
 
J

John W. Krahn

Ben said:
I would use something more like (untested)

find . -type f | xargs perl -0377 -pi -e'/<string here>/ and
s,(FILEDIR)="/opt/ ([^/]+) / ([^"]+) ",$1="/new/$2/$3",gx'

(actually I'd probably do the whole thing in Perl, using
File::Find::Rule, but this is a more shellish solution). The -0377 says
to read the whole file in one go, which allows you to omit the grep
altogether while still using perl -p.

That may not work correctly as 0377 is a possible valid character.

perldoc perlrun
[ SNIP ]
-0[digits]
specifies the input record separator (`$/') as an
octal number. If there are no digits, the null
character is the separator. Other switches may
precede or follow the digits. For example, if you
have a version of find which can print filenames
terminated by the null character, you can say this:

find . -name '*.orig' -print0 | perl -n0e unlink

The special value 00 will cause Perl to slurp files
in paragraph mode. The value 0777 will cause Perl to
slurp files whole because there is no legal character
with that value.



John
 
M

Martijn Lievaart

You need to learn about xargs. find without xargs is practically
useless. Something like

find . | xargs grep -l <string> | xargs sed -i -Ee'...'

(-r instead of -E for GNU sed, or omit if you can stand BREs :) ).

Not so. The while construct reads lines, so filenames with spaces get
interpreted correctly. Xargs has the nasty behaviour to seperate on
whitespace. Obviously to handle filenames with newlines you need find -
exec or the gnu extensions find -print0 | xargs -0.

In short, use find -0 | xargs -0 if available and portability is not an
issue, use -exec otherwise. Only use while read if really needed. Never
use find | xargs unless you are absolutely positive there is no
whitespace in any filename.

HTH,
M4
 
T

Tad J McClellan

Daryl Rose said:
they have a single line in them that define a specific
path. i.e. FILEDIR="/opt/<subdir>/file"

This path needs to be changed. The opt directory is the only
consistent within this path. The name of the subdir, and the file
name change.


Then you meant "e.g." instead of "i.e.".

http://www.wsu.edu/~brians/errors/e.g.html


perl -ip -e 's/SEARCH/REPLACE/' $var1/$var2
^
^

That code will not change the contents of any files (because
it does not make any output).

perl -i -p -e 's/SEARCH/REPLACE/' $var1/$var2
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top