Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Andreas Schwab
Greg Wooledge  writes:

> And testing:
>
> imadev:~$ file=$HOME/x
> imadev:~$ link=$(command ls -l -- "$file"; printf x)
> imadev:~$ link=${link%$'\nx'}
> imadev:~$ remove="$file -> "
> imadev:~$ file=${link#*$remove}

This lacks a pair of quotes (${link#*"$remove"}).  Testcase: 'x[a]' -> 'y'.

Andreas.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."





Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Bernd Eggink

Am 12.02.2010 15:39, schrieb Greg Wooledge:

On Fri, Feb 12, 2010 at 02:53:39PM +0100, Bernd Eggink wrote:

I once wrote a more generic shell function for this purpose, see:
   http://sudrala.de/en_d/shell-getlink.html


You note that it doesn't handle names containing ->, which is true.
I'll get back to that at the end.

It also won't handle any name that "ls -l" will refuse to print out
correctly on any given system.

Also, there are three more cases that it can't handle.  The first is
due to missing quotes in your command:

 echo ${link##*->  }

Without quotes, this will mangle all leading, trailing or repeated
whitespace.  Easily fixed by adding the quotes.  (There are a few
other cases of missing quotes too.)


Thanks. I knew there were some missing cases, but when I wrote it, I 
didn't consider hardening the function against insane filenames worth 
the effort.
However, it now begins to interest me if this is common practice. How 
big is the probability to stumble upon such filenames is in real life?


Bernd

--
Bernd Eggink
http://sudrala.de




Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Bob Proulx
Greg Wooledge wrote:
> That leaves names which contain ->.  The tricky part here is that we
> can't easily tell whether an extra -> is in the symbolic link or in
> the target.
> 
> imadev:~$ ln -s tmp 'x -> y'
> imadev:~$ ln -s 'y -> tmp' x
> imadev:~$ ls -ld x*
> lrwxr-xr-x   1 wooledgpgmr 8 Feb 12 09:28 x -> y -> tmp
> lrwxr-xr-x   1 wooledgpgmr 3 Feb 12 09:28 x -> y -> tmp
> 
> However, there actually is enough information available to extract
> the desired part.  When we call ls -l, we're passing it the filename
> we're resolving.  So we already know the source name.  Removing the
> source name and the ' -> ' which follows it should leave us with the
> target name.
> 
> link=$(command ls -l -- "$file"; printf x)
> link=${link%$'\nx'}
> remove="$file -> "
> file=${link#*$remove}

Your solution using the original filename is better but I thought I
would point out that the size of the target value is also displayed by
'ls -l'.  In the above the value "tmp" is 3 characters and "y -> tmp"
is 8 characters and that value is displayed in the size field.  So
even without knowing the filename to be listed the result can be
parsed to extract the target name.

Bob




Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Greg Wooledge
On Fri, Feb 12, 2010 at 02:53:39PM +0100, Bernd Eggink wrote:
> I once wrote a more generic shell function for this purpose, see:
>   http://sudrala.de/en_d/shell-getlink.html

You note that it doesn't handle names containing ->, which is true.
I'll get back to that at the end.

It also won't handle any name that "ls -l" will refuse to print out
correctly on any given system.  (I don't know any specific cases off
hand, though.  When stdout isn't a terminal, both Debian and OpenBSD
seem to stop converting weird bytes into question marks.  And HP-UX
gladly prints weird bytes even when stdout is a terminal.  But there
could be some strange legacy Unix systems out there where ls doesn't
print things as expected.)

Also, there are three more cases that it can't handle.  The first is
due to missing quotes in your command:

echo ${link##*-> }

Without quotes, this will mangle all leading, trailing or repeated
whitespace.  Easily fixed by adding the quotes.  (There are a few
other cases of missing quotes too.)

The second is a target named -n or -e.  "echo -n" or "echo -e" will
print nothing.  Again, this is easily fixed by replacing echo with
printf "%s\n" (assuming you want to continue printing the newline).

The third case is harder.  Trailing newlines will be eaten up by the
command substitution here:

link=$(command ls -l "$file")

This is somewhat complicated by the fact that "ls -l" adds a newline,
which you do want to remove; but you don't want to remove a newline
that's actually part of the filename.

The only trick I know for getting the output of a command into a variable,
*including trailing newlines*, is this:

variable=$(some command; printf x); variable=${variable%x}

Or in your case, since you want to remove precisely one newline (even if
there are more than one):

link=$(command ls -l -- "$file"; printf x)
link=${link%$'\nx'}

That leaves names which contain ->.  The tricky part here is that we
can't easily tell whether an extra -> is in the symbolic link or in
the target.

imadev:~$ ln -s tmp 'x -> y'
imadev:~$ ln -s 'y -> tmp' x
imadev:~$ ls -ld x*
lrwxr-xr-x   1 wooledgpgmr 8 Feb 12 09:28 x -> y -> tmp
lrwxr-xr-x   1 wooledgpgmr 3 Feb 12 09:28 x -> y -> tmp

However, there actually is enough information available to extract
the desired part.  When we call ls -l, we're passing it the filename
we're resolving.  So we already know the source name.  Removing the
source name and the ' -> ' which follows it should leave us with the
target name.

link=$(command ls -l -- "$file"; printf x)
link=${link%$'\nx'}
remove="$file -> "
file=${link#*$remove}

And testing:

imadev:~$ file=$HOME/x
imadev:~$ link=$(command ls -l -- "$file"; printf x)
imadev:~$ link=${link%$'\nx'}
imadev:~$ remove="$file -> "
imadev:~$ file=${link#*$remove}
imadev:~$ printf "<%s>\n" "$file"
 tmp>
imadev:~$ file=$HOME/'x -> y'
imadev:~$ link=$(command ls -l -- "$file"; printf x)
imadev:~$ link=${link%$'\nx'}
imadev:~$ remove="$file -> "
imadev:~$ file=${link#*$remove}
imadev:~$ printf "<%s>\n" "$file"





Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Bernd Eggink

Am 12.02.2010 14:38, schrieb Guillaume Outters:

Greg a écrit :


Except that HP-UX 10.20 and HP-UX 11.11 don't have readlink(1).
(Maybe it's added in 11.2x?  I don't know.)


You're right. I must admit I made a concession to some GNU coreutils tools on the platform. 
I once used some ls -l "$SCRIPTS" | sed -e 's/.* ->  //' magic to replace it 
(and it worked two minutes ago on the HP-UX, just like it used to back in the old days).


I once wrote a more generic shell function for this purpose, see:
  http://sudrala.de/en_d/shell-getlink.html

Bernd

--
Bernd Eggink
http://sudrala.de




Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Guillaume Outters
Greg a écrit :

> Except that HP-UX 10.20 and HP-UX 11.11 don't have readlink(1).
> (Maybe it's added in 11.2x?  I don't know.)

You're right. I must admit I made a concession to some GNU coreutils tools on 
the platform. I once used some ls -l "$SCRIPTS" | sed -e 's/.* -> //' magic to 
replace it (and it worked two minutes ago on the HP-UX, just like it used to 
back in the old days).

-- 
Guillaume




Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Greg Wooledge
On Fri, Feb 12, 2010 at 11:56:49AM +0100, Guillaume Outters wrote:
> 
> I usually begin all my scripts with this beast:
> 
> absolutiseScripts() { SCRIPTS="$1" ; echo "$SCRIPTS" | grep -q ^/ || 
> SCRIPTS="`dirname "$2"`/$SCRIPTS" ; } ; absolutiseScripts "`command -v "$0"`" 
> "`pwd`/." ; while [ -h "$SCRIPTS" ] ; do absolutiseScripts "`readlink 
> "$SCRIPTS"`" "$SCRIPTS" ; done ; SCRIPTS="`dirname "$SCRIPTS"`"
> 
> I use it with bash on Mac OS X, FreeBSD, Linux, and it seems (just tested now 
> at work) that HP/UX 11 with its bare sh can handle it.

Except that HP-UX 10.20 and HP-UX 11.11 don't have readlink(1).
(Maybe it's added in 11.2x?  I don't know.)




Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Guillaume Outters
Marc a écrit :

>source  $(dirname "$0")/functions.sh

I usually begin all my scripts with this beast:

absolutiseScripts() { SCRIPTS="$1" ; echo "$SCRIPTS" | grep -q ^/ || 
SCRIPTS="`dirname "$2"`/$SCRIPTS" ; } ; absolutiseScripts "`command -v "$0"`" 
"`pwd`/." ; while [ -h "$SCRIPTS" ] ; do absolutiseScripts "`readlink 
"$SCRIPTS"`" "$SCRIPTS" ; done ; SCRIPTS="`dirname "$SCRIPTS"`"

I use it with bash on Mac OS X, FreeBSD, Linux, and it seems (just tested now 
at work) that HP/UX 11 with its bare sh can handle it.

It does a lot of symlink-resolution, because I typically store my scripts in an 
src/scripts directory, with symlinks from $HOME/bin/tagadatsointsoin to 
$HOME/src/scripts/tagadatsointsoin.

-- 
Guillaume




Re: Is there a special variable for the directory where the script is in?

2010-02-12 Thread Marc Herbert
pk a écrit :
> Peng Yu wrote:
> 
>> $0 gives the file name of the script. I could use several shell
>> command to get the directory where the script is in. But I'm wondering
>> if there is an easy-to-use variable that refers to the directory where
>> the script is in?
> 
> See this page:
> 
> http://mywiki.wooledge.org/BashFAQ/028

This is well informed, very useful and very interesting page is
considering the case where:

- you want your widely distributed and very portable script to be called
  in any way from anywhere (including from a pipe from Mars).
- hard-coding the location of your configuration files and libraries is
  not a problem.

I am sure this is the most common case. But this is definitely not my
case. Actually, my requirements are *the exact opposite*. For instance I
do not want anyone to use my script but me. So I just do this instead:

   source  $(dirname "$0")/functions.sh

The fact that it might break whenever someone else uses my script in a
way I did not plan is a feature (in this respect, this code is even too
robust).





Re: Is there a special variable for the directory where the script is in?

2010-02-11 Thread Chris F.A. Johnson
On Thu, 11 Feb 2010, Eric Blake wrote:

> According to Chris F.A. Johnson on 2/11/2010 4:23 PM:
> > On Fri, 12 Feb 2010, Peng Yu wrote:
> > 
> >> $0 gives the file name of the script. I could use several shell
> >> command to get the directory where the script is in. But I'm wondering
> >> if there is an easy-to-use variable that refers to the directory where
> >> the script is in?
> > 
> >   $0 normally gives the full path to the file, so: "${0%/*}"
> 
> No, $0 normally gives the argv[0], which matches how the file was invoked.

   Or, if it was found in $PATH, the full path to the file.

   That is how scripts are "normally" executed.

>  If it was invoked by absolute path (or even an anchored invocation, such
> as ./script), then you can compute it yourself.
>
>  Otherwise, you have to
> recreate the PATH walk in your script to determine where the script was
> eventually located, and hope that the script was not invoked in such a way
> that argv[0] does not match the name of the script being run.
> 
> Look at any configure script generated by autoconf for a sample of how
> complex it can be to portably locate $myself.

   And, of course, there is rarely a good reason to need to know the
   location.

-- 
   Chris F.A. Johnson  
   ===
   Author:
   Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
   Pro Bash Programming: Scripting the GNU/Linux Shell (2009, Apress)




Re: Is there a special variable for the directory where the script is in?

2010-02-11 Thread Eric Blake
According to Chris F.A. Johnson on 2/11/2010 4:23 PM:
> On Fri, 12 Feb 2010, Peng Yu wrote:
> 
>> $0 gives the file name of the script. I could use several shell
>> command to get the directory where the script is in. But I'm wondering
>> if there is an easy-to-use variable that refers to the directory where
>> the script is in?
> 
>   $0 normally gives the full path to the file, so: "${0%/*}"

No, $0 normally gives the argv[0], which matches how the file was invoked.
 If it was invoked by absolute path (or even an anchored invocation, such
as ./script), then you can compute it yourself.  Otherwise, you have to
recreate the PATH walk in your script to determine where the script was
eventually located, and hope that the script was not invoked in such a way
that argv[0] does not match the name of the script being run.

Look at any configure script generated by autoconf for a sample of how
complex it can be to portably locate $myself.

-- 
Don't work too hard, make some time for fun as well!

Eric Blake e...@byu.net



signature.asc
Description: OpenPGP digital signature


Re: Is there a special variable for the directory where the script is in?

2010-02-11 Thread pk
Peng Yu wrote:

> $0 gives the file name of the script. I could use several shell
> command to get the directory where the script is in. But I'm wondering
> if there is an easy-to-use variable that refers to the directory where
> the script is in?

See this page:

http://mywiki.wooledge.org/BashFAQ/028



Re: Is there a special variable for the directory where the script is in?

2010-02-11 Thread Chris F.A. Johnson
On Fri, 12 Feb 2010, Peng Yu wrote:

> $0 gives the file name of the script. I could use several shell
> command to get the directory where the script is in. But I'm wondering
> if there is an easy-to-use variable that refers to the directory where
> the script is in?

  $0 normally gives the full path to the file, so: "${0%/*}"

-- 
   Chris F.A. Johnson  
   ===
   Author:
   Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
   Pro Bash Programming: Scripting the GNU/Linux Shell (2009, Apress)




Is there a special variable for the directory where the script is in?

2010-02-11 Thread Peng Yu
$0 gives the file name of the script. I could use several shell
command to get the directory where the script is in. But I'm wondering
if there is an easy-to-use variable that refers to the directory where
the script is in?