Paul L. Snyder on 23 Aug 2009 20:25:35 -0700


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [PLUG] the character least likely to find in a Unix file name


On Sun, 23 Aug 2009, Walt Mankowski wrote:

> On Sun, Aug 23, 2009 at 10:11:01PM -0400, TuskenTower wrote:
> > One more question on this.  Which code pattern would you prefer for
> > modifying $PATH?  We have an env var that is in $PATH and we are
> > replacing it with a new one.  That is why the sed command is built
> > using double quotation marks and have dollar-variables in them.
> > 
> >   PATH=`echo $PATH | sed "s"'$'"$old_phat"'$'"$new_path"'$'`
> > 
> > OR
> > 
> >   PATH=`echo $PATH | sed "s;$old_path;$new_path;"`
> 
> I guess I probably could have been more explicit in my original post,
> but the reason I suggested using perl instead of awk was that with
> perl you can pass in old_path and new_path as command-line parameters
> and avoid these quoting issues.

Walt is extremely right...using Perl will make many of these shell
shenanigans unnecessary.  Use it if you can.

Operating on the assumption that you can't rely on Perl being installed on
every platform that your script is going to be run on, though, here are my
thoughts:

Both of the above are a bad idea.  The first will break if there is a '$'
in the path and the second if there is a ';'.  Furthermore, even if they
don't break they might replace the wrong thing.  The following illustrates
the point.

--------------------------------------------------------------------------
#!/bin/sh

# We want to replace '/bin' with '/fom' in PTH
# /bin and /fom are stored in environment variables
PTH=/usr/bin:/bin
old_path=/bin
new_path=/fom

# We can preprocess the envvars to make them safe for
# sed, but notice if we do it this way (as opposed to
# my previous suggestion, where we nested them in $()s)
# we have to use a double layer of escapes.  Shell
# programming is icky that way.
OP=`echo $old_path | sed 's:/:\\\\/:g'`
NP=`echo $new_path | sed 's:/:\\\\/:g'`

# If we simply interpolate and try to replace the string...
naive=`echo $PTH | sed "s/$OP/$NP/"`

# We end up with '/usr/fom:/bin'.  Oops!
echo Naive: $naive

# So, we get ugly:
PTH=`echo $PTH|sed 's/:/\n/g'|sed "s/^$OP\$/$NP/"|tr '\n' ':'|head -c-1`

# The first sed breaks PTH into lines using ':' as the delimiter
# This may be problematic on some seds, may need to use a literal
# (escaped) new-line.
# The second sed does the substitution, but only if OP matches the
# entire entry.
# The tr joins the string back together again with ':'.
# Unfortunately, the tr leaves us with an extra ': at the end;
# the head strips it off.  Not sure if the -c-1 is portable, check
# before relying on it.

echo Better: $PTH
----------------------------------------------------------------------------

Hope this helps,
Paul
___________________________________________________________________________
Philadelphia Linux Users Group         --        http://www.phillylinux.org
Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce
General Discussion  --   http://lists.phillylinux.org/mailman/listinfo/plug