Need help integrating a perl command into a shell script.

Discussion in 'Perl Misc' started by Daryl Rose, Dec 13, 2007.

  1. Daryl Rose

    Daryl Rose Guest

    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
     
    Daryl Rose, Dec 13, 2007
    #1
    1. Advertising

  2. Daryl Rose wrote:
    > 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.

    >
    >
    > 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?
    >
     
    RedGrittyBrick, Dec 13, 2007
    #2
    1. Advertising

  3. Daryl Rose

    Ben Morrow Guest

    Quoth 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.


    You haven't said what you want to change it to. I'm assuming you want to
    change it to FILEDIR="/new/<subdir>/file", if this isn't the case edit
    appriately below.

    > 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
     
    Ben Morrow, Dec 13, 2007
    #3
  4. Ben Morrow wrote:
    >
    > 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
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, Dec 13, 2007
    #4
  5. On Thu, 13 Dec 2007 15:16:31 +0000, Ben Morrow wrote:

    > Quoth Daryl Rose <>:
    >> 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 :) ).


    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
     
    Martijn Lievaart, Dec 13, 2007
    #5
  6. Daryl Rose <> wrote:

    > 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



    --
    Tad McClellan
    email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"
     
    Tad J McClellan, Dec 14, 2007
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    5,888
    Jonathan Bromley
    Feb 18, 2005
  2. dpackwood
    Replies:
    3
    Views:
    1,859
  3. Ranyart
    Replies:
    5
    Views:
    182
    James Willmore
    Aug 30, 2003
  4. moongeegee

    execute a shell script in a shell script

    moongeegee, Dec 3, 2007, in forum: Perl Misc
    Replies:
    2
    Views:
    276
    Ben Morrow
    Dec 4, 2007
  5. Thomas
    Replies:
    2
    Views:
    120
    sisyphus
    Sep 3, 2008
Loading...

Share This Page