Re: A very interesting sed question

Re: A very interesting sed question

am 30.01.2008 19:33:04 von someone

lguo.us@gmail.com wrote:
> I apologize for crossing groups posting ...
>
> Here is my interesting sed question:
>
> echo "/usr/bin:/etc:/usr/local/bin:/opt:/opt/bin" | sed "s?/usr.*:??g"
>
> What I wanted to see for sed "s?/usr.*:??g" is to remove any
> directories containing "/usr" from the string. The correct result
> should be like:
>
> /etc:/opt/:/opt/bin
>
> However, the above sed command doesn't do what I wanted, it returns
> the last directory only.
>
> /opt/bin
>
> so apparently the colon (:) in the sed command matches the last one
> in the string, not the first one after the pattern. How do I fix it?

As others have said the * quantifier is greedy so you could use

$ echo "/usr/bin:/etc:/usr/local/bin:/opt:/opt/bin" | sed -e
's?/usr[^:]*:??g'
/etc:/opt:/opt/bin

But that won't work correctly if the last entry contains '/usr'

$ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
's?/usr[^:]*:??g'
/opt/bin:/opt:/etc:/usr/bin

So you could try it like this

$ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
's?/usr[^:]*\(:\|$\)??g'
/opt/bin:/opt:/etc:

But that leaves a ':' at the end of the string

$ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
's?/usr[^:]*\(:\|$\)??g' -e 's?:$??'
/opt/bin:/opt:/etc



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall

Re: A very interesting sed question

am 30.01.2008 19:56:25 von Stephane CHAZELAS

On Wed, 30 Jan 2008 18:33:04 GMT, John W. Krahn wrote:
[...]
> $ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
> 's?/usr[^:]*\(:\|$\)??g' -e 's?:$??'
> /opt/bin:/opt:/etc
[...]

The \(..\|...\) alternation syntax is not standard.

The above also removes a trailing : that would have been there
from the start. It also removes /usr in /opt/usrank/...

sed '
s,^,:,
s,:/usr[^:]*,,g
s,^$,/non-existent,
s,^:,,'

note that an empty PATH contains one entry: the current
directory. So you need to have PATH=/non-existent ifever you
remove all the entries. ("/usr/local/bin:" should be changed to
"" (the current directory), and "/usr/local/bin" to
"/some-inexistent-dir").

--
Stephane

Re: A very interesting sed question

am 30.01.2008 20:55:19 von someone

Stephane Chazelas wrote:
> On Wed, 30 Jan 2008 18:33:04 GMT, John W. Krahn wrote:
> [...]
>> $ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
>> 's?/usr[^:]*\(:\|$\)??g' -e 's?:$??'
>> /opt/bin:/opt:/etc
> [...]
>
> The \(..\|...\) alternation syntax is not standard.
>
> The above also removes a trailing : that would have been there
> from the start. It also removes /usr in /opt/usrank/...
>
> sed '
> s,^,:,
> s,:/usr[^:]*,,g
> s,^$,/non-existent,
> s,^:,,'
>
> note that an empty PATH contains one entry: the current
> directory. So you need to have PATH=/non-existent ifever you
> remove all the entries. ("/usr/local/bin:" should be changed to
> "" (the current directory), and "/usr/local/bin" to
> "/some-inexistent-dir").

perl -lne'print join ":", grep !m(/usr), split /:/'



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall

Re: A very interesting sed question

am 31.01.2008 10:43:32 von Stephane CHAZELAS

On Wed, 30 Jan 2008 19:55:19 GMT, John W. Krahn wrote:
> Stephane Chazelas wrote:
>> On Wed, 30 Jan 2008 18:33:04 GMT, John W. Krahn wrote:
>> [...]
>>> $ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
>>> 's?/usr[^:]*\(:\|$\)??g' -e 's?:$??'
>>> /opt/bin:/opt:/etc
>> [...]
>>
>> The \(..\|...\) alternation syntax is not standard.
>>
>> The above also removes a trailing : that would have been there
>> from the start. It also removes /usr in /opt/usrank/...
>>
>> sed '
>> s,^,:,
>> s,:/usr[^:]*,,g
>> s,^$,/non-existent,
>> s,^:,,'
>>
>> note that an empty PATH contains one entry: the current
>> directory. So you need to have PATH=/non-existent ifever you
>> remove all the entries. ("/usr/local/bin:" should be changed to
>> "" (the current directory), and "/usr/local/bin" to
>> "/some-inexistent-dir").
>
> perl -lne'print join ":", grep !m(/usr), split /:/'
[...]

Nope, won't do.

perl's split ignores the leading and trailing ":" so can't be
used to split $PATH that way. See also my comment about an empty
$PATH.

echo "/bin:/usr/bin:" |
perl -lne'print join ":", grep !m(/usr), split /:/'

gives "/bin", it removed the current dir.

echo "/usr/bin" |
perl -lne'print join ":", grep !m(/usr), split /:/'

gives "", it *adds* the current dir.

--
Stephane

Re: A very interesting sed question

am 31.01.2008 14:13:55 von someone

Stephane Chazelas wrote:
> On Wed, 30 Jan 2008 19:55:19 GMT, John W. Krahn wrote:
>> Stephane Chazelas wrote:
>>> On Wed, 30 Jan 2008 18:33:04 GMT, John W. Krahn wrote:
>>> [...]
>>>> $ echo "/opt/bin:/opt:/usr/local/bin:/etc:/usr/bin" | sed -e
>>>> 's?/usr[^:]*\(:\|$\)??g' -e 's?:$??'
>>>> /opt/bin:/opt:/etc
>>> [...]
>>>
>>> The \(..\|...\) alternation syntax is not standard.
>>>
>>> The above also removes a trailing : that would have been there
>>> from the start. It also removes /usr in /opt/usrank/...
>>>
>>> sed '
>>> s,^,:,
>>> s,:/usr[^:]*,,g
>>> s,^$,/non-existent,
>>> s,^:,,'
>>>
>>> note that an empty PATH contains one entry: the current
>>> directory. So you need to have PATH=/non-existent ifever you
>>> remove all the entries. ("/usr/local/bin:" should be changed to
>>> "" (the current directory), and "/usr/local/bin" to
>>> "/some-inexistent-dir").
>> perl -lne'print join ":", grep !m(/usr), split /:/'
> [...]
>
> Nope, won't do.
>
> perl's split ignores the leading and trailing ":" so can't be
> used to split $PATH that way. See also my comment about an empty
> $PATH.
>
> echo "/bin:/usr/bin:" |
> perl -lne'print join ":", grep !m(/usr), split /:/'
>
> gives "/bin", it removed the current dir.

$ echo "/bin:/usr/bin:" | perl -lne'print join ":", grep !m(/usr), split
/:/, $_, -1'
/bin:


> echo "/usr/bin" |
> perl -lne'print join ":", grep !m(/usr), split /:/'
>
> gives "", it *adds* the current dir.

Isn't "." the current directory?



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall

Re: A very interesting sed question

am 31.01.2008 14:36:06 von Stephane CHAZELAS

On Thu, 31 Jan 2008 13:13:55 GMT, John W. Krahn wrote:
[...]
> $ echo "/bin:/usr/bin:" | perl -lne'print join ":", grep !m(/usr), split
> /:/, $_, -1'
> /bin:
>
>
>> echo "/usr/bin" |
>> perl -lne'print join ":", grep !m(/usr), split /:/'
>>
>> gives "", it *adds* the current dir.
>
> Isn't "." the current directory?
[...]

"." is the "." dir in the current directory (which generally is
the same as the current directory). "" is the current directory.

"/bin" means search in /bin only.

"/bin:" means search in /bin and the current directory
execvp("foo"...), will do:
execve("/bin/foo"...);
execve("foo"...);

"/bin:." means search in /bin and "."
execvp("foo"...), will do:
execve("/bin/foo"...);
execve("./foo"...);

"" means search in the current directory. There's no way to
specify: don't even try searching, so the work around is to
include only non-existing directories in $PATH. If you unset
PATH, a default value of PATH will be used.

"." means an additional lookup and may fail on filesystems that
don't have a "." entry but is safer with regards to scripts for
which the option terminator has been forgotten on the shebang
line (#! /bin/sh instead of #! /bin/sh -).

--
Stephane