Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

POSIX equivalent to readlink utility ?

2,399 views
Skip to first unread message

Timothy Madden

unread,
Dec 10, 2011, 8:06:15 AM12/10/11
to
Hello

Is there something like a `readlink´ command in POSIX, or a way to get
the same effect and get the file a link points to ?

Currently, if I want a portable script, I need to do
if command -v readlink >/dev/null
then
: # use readlink here ...
fi

Thank you,
Timothy Madden

Ben Bacarisse

unread,
Dec 10, 2011, 10:37:10 AM12/10/11
to
Timothy Madden <termin...@gmail.com> writes:

> Is there something like a `readlink´ command in POSIX, or a way to get
> the same effect and get the file a link points to ?

There is always ls -dl

L=$(ls -dl link)
echo ${L#*-> }

(nit: fails if the link's name includes "-> ")

Also, though not POSIX, you might find that

find link -prune -printf %l

is available and does what you want.

<snip>
--
Ben.

Stachu 'Dozzie' K.

unread,
Dec 11, 2011, 8:18:15 AM12/11/11
to
Also, though not POSIX, one might use quite common Perl interpreter:
#v+
#!/usr/bin/env perl -l
my $target = readlink shift or die "Error: $!\n";
print $target;
#v-

--
Secunia non olet.
Stanislaw Klekot

Timothy Madden

unread,
Dec 11, 2011, 3:12:50 PM12/11/11
to
Thank you. The `ls´ option is good enough I think.
I never though POSIX would specify the way `ls´ should format its
output, so I did not rely on that formatting, but if I check the
standard I see that it does specify that `ls -l´ should output
'linkpath -> filepath'
exactly.
My link does not include '-> ' in the file name, so that would be ok.

Thank you,
Timothy Madden

bsh

unread,
Dec 15, 2011, 9:17:43 PM12/15/11
to
Timothy Madden <terminato...@gmail.com> wrote:
> Ben Bacarisse wrote:
> > Timothy Madden<terminato...@gmail.com>  writes:
> > > ...
> Thank you. The `ls´ option is good enough I think.
> I never though POSIX would specify the way `ls´ should format its
> output, so I did not rely on that formatting, but if I check the
> standard I see that it does specify that `ls -l´ should output
>         'linkpath -> filepath'
> exactly.
> My link does not include '-> ' in the file name, so that would be ok.

It's even a bit more complicated than that, insofar as the number of
ls(1)
fields will vary if the create/access/modify time of the given
filename is newer
than a certain internally defined period. Also, the output format for
BSD-derived
and SysV-derived ls(1)es are fundamentally different.

Here is a ksh(1) function that does all the hard stuff. It is well-
used and well-
checked. Additional optional features are the ability to do path
lookup,
multiple symlink traversal, and physical versus logical paths. Refer
to the
embedded manpage to have a sense of what needs to be accounted for.

=Brian

#! /bin/echo error: only source
#*TAG:
# Author: Brian Hiles <b...@iname.com>
# Copyright: (c) 2008
# Description: resolve and canonicize full pathname of arguments
# Name: resolvepath
# Project: @(#)resolvepath.sh 1.9 1997/12 b...@iname.com (Brian Hiles)
# Requires:
# See-also: File-PathConvert-0.4.tar (perl)
# See-also: pathconvert: http://wafu.netgate.net/tama/unix/indexe.html
(C)
# Usage: resolvepath [-hlp] path...
# Version: 1.09

#01
function resolvepath # [-hlp] path...
{ set -o noglob
# Ksh Bug: OPTIND cannot be declared integer!
OPTIND=1 typeset -i rc=0
typeset IFS OPTARG arg dir fn headers= symlink= oarg opt usepath=
while getopts :HhLlPp opt
do case $opt in
(h) headers=ON ;;
(+h|H) headers=OFF ;;
(l) symlink=ON ;;
(+l|L) symlink= ;;
(p) usepath=ON ;;
(+p|P) usepath= ;;
([:?]) print -ru2 "usage: $0 [-hlp] path...
-h - prepend the output with argument header
-l - show logical path with symlinks resolved [physical path]
-p - apply path lookup, if applicable"
return 2 ;;
esac
done
shift OPTIND-1
if [[ $headers = OFF ]]
then headers=
else (($#>1)) && headers=ON
fi
for arg
do oarg=$arg
if [[ $usepath = ON && ! -d $arg ]]
then # Ksh Bug: "whence" cannot handle args with spaces
arg=$( if whence -p "$arg"
then print -ru2 \
'resolvepath: whence: error: "\"$oarg\" not found"
rc=rc+1 continue
fi
)
fi
if [[ -a $arg ]]
then print -ru2 "resolvepath: error: \"$arg\" not found"
rc=rc+1 continue
fi
[[ $arg != */* ]] && arg="./$arg"
if [[ -d $arg ]]
then dir=$arg fn=
else dir=${arg%/*} fn=${arg##*/}
fi
${DIAG:+print -ru2 "[ $0: dirpart=\"$dir\", filepart=\"$fn\" ]"}
# Ksh Bug: "cd -P dir" works, but "cd -P -- dir" does not!
[[ $dir = -* ]] && dir="./$dir" # work-around for above bug
\cd ${symlink:+-P} "$dir" || rc=rc+1 continue
print -r -- "${headers:+$oarg: }${PWD%/}/$fn" # <= TAB
\cd - >&-
done
return $rc
}

#02 EMBEDDED MAN-PAGE FOR "src2man"
: '
#++
NAME
resolvepath - resolve and canonicize the full pathname of argument

SYNOPSIS
resolvepath [-hlp] path...

OPTIONS
-h - Prepend the output with argument header.
-l - Show logical path with symlinks resolved. [physical path]
-p - Apply path lookup, if applicable.

DESCRIPTION
...

The directory components are guaranteed to be separated by one
and only one slash ("/") character.

If and only if the path is a directory, the output is guaranteed
to be terminated with one slash ("/") character.

RETURN CODE
Returns 0 if successful, 2 for options parsing errors, otherwise
the number of arguments in error.

EXAMPLE
$ resolvepath .
/home/brian/side/lib/

$ resolvepath cat
resolvepath: error: "cat" not found
$ resolvepath -p cat
/bin/cat
$ resolvepath -lp cat
/usr/bin/cat

$ resolvepath /
/
$ resolvepath //
/
$ resolvepath /..
/
$ resolvepath /.//..///.////../////.//////..///////.////////..
/

ENVIRONMENT
PATH

SEE ALSO
predictshell(3S), stat(3S)

AUTHOR
Brian Hiles <b...@iname.com>

CAVEATS
The algorithm that is used requires the directory component of
the resolved argument to be executable; i.e. you must have
permission to chdir to it.

BUGS
Filenames with embedded spaces will be failed to be recognized;
this is a bug in the ksh builtin "whence", not resolvepath(3S).

#--
'

Barry Margolin

unread,
Dec 16, 2011, 2:42:46 AM12/16/11
to
In article
<5f9d0ee3-7fcf-497c...@r16g2000prr.googlegroups.com>,
bsh <brian...@rocketmail.com> wrote:

> It's even a bit more complicated than that, insofar as the number of
> ls(1)
> fields will vary if the create/access/modify time of the given
> filename is newer
> than a certain internally defined period.

No it doesn't. It's either "Mon Day Time" or "Month Day Year", but
either way it's the same number of fields. I expect this was by design.

However, if the filename contains whitespace, that will mess up column
counting.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Timothy Madden

unread,
Dec 16, 2011, 5:56:15 AM12/16/11
to
On 16.12.2011 04:17, bsh wrote:
> Timothy Madden<terminato...@gmail.com> wrote:
>> Ben Bacarisse wrote:
>>> Timothy Madden<terminato...@gmail.com> writes:
>>>> ...
>> Thank you. The `ls´ option is good enough I think.
>> I never though POSIX would specify the way `ls´ should format its
>> output, so I did not rely on that formatting, but if I check the
>> standard I see that it does specify that `ls -l´ should output
>> 'linkpath -> filepath'
>> exactly.
>> My link does not include '-> ' in the file name, so that would be ok.
>
> It's even a bit more complicated than that, insofar as the number of
> ls(1)
> fields will vary if the create/access/modify time of the given
> filename is newer
> than a certain internally defined period. Also, the output format for
> BSD-derived
> and SysV-derived ls(1)es are fundamentally different.

Sorry but I do not see the problem here. I do not really parse the
output from `ls´, I just use:
${ls_output#*"${link_name} -> "}
parameter expansion format, in my shell script.

The dates/permissions/other fields may be printed in any possible way,
as long as the line ends with "${link_name} -> ${actual_file}", which
POSIX says it should end with.

To be correct, I can not see /any/ possible case where this substitution
would fail to return the actual file being linked.

Thank you,
Timothy Madden

Geoff Clare

unread,
Dec 16, 2011, 8:42:57 AM12/16/11
to
Timothy Madden wrote:

> Sorry but I do not see the problem here. I do not really parse the
> output from `ls´, I just use:
> ${ls_output#*"${link_name} -> "}
> parameter expansion format, in my shell script.
>
> The dates/permissions/other fields may be printed in any possible way,
> as long as the line ends with "${link_name} -> ${actual_file}", which
> POSIX says it should end with.
>
> To be correct, I can not see /any/ possible case where this substitution
> would fail to return the actual file being linked.

Neither can I, for the substitution itself. However, if you
assign ls_output using a simple:

ls_output=$(ls -l -- "${link_name}")

then the result would be incorrect if the target of the link ends
with a newline.

--
Geoff Clare <net...@gclare.org.uk>

bsh

unread,
Dec 16, 2011, 5:20:53 PM12/16/11
to
Barry Margolin <bar...@alum.mit.edu> wrote:
> <5f9d0ee3-7fcf-497c-93d1-20fa2e719...@r16g2000prr.googlegroups.com> wrote:
>  bsh <brian_hi...@rocketmail.com> wrote:
> > ...

> However, if the filename contains whitespace, that will mess up column
> counting.

... Including that darned "=>" token....

> > It's even a bit more complicated than that, insofar as the number of
> > ls(1) fields will vary if the create/access/modify time of the given
> > filename is newer than a certain internally defined period.
> No it doesn't. It's either "Mon Day Time" or "Month Day Year", but
> either way it's the same number of fields.

Yes, it does.

I was speaking to the algorithm (and fundamental issue) posed by the
OQ,
not pertaining to the algorithm used by resolvepath, which is not the
one
utilized in this function exactly because of this weakness, as
discussed.
Instead of directly rebuting your assertion, let me speak
metalogically:
how could I NOT be correct, insofar as I am the author of it, its era
of
authorship before Y2K and POSIX conformance, the addressed criterion
of portability between BSD and SysV versions of ls(1), and the
relative
ease of determining the historical validity of the stated behavior.

Like many of my function library, resolvepath was originally a bourne
shell function, and later ported to the more full featured ksh(1). I
wrote
another function, stat, than also was originally wrote in sh(1), and
was
called by that original resolvepath.sh. The above issue is documented
and worked around fully in that, including:

"Only when the file is less than six months old will the timestamp
(access-, create-, or mod-time) information be available to
calculate
a floating point remainder of a day when given the -r option."

#! /bin/echo error: only source
#*TAG:06847-11:1975-02-23:0644:stat:
# Author: "Brian Hiles" <b...@iname.com>
# Date: 2003-01-04
# Description: shell emulation of stat(2)/lstat(2)
# License: copyright (c) 1998-2011
# Name: stat
# Project: @(#)stat.sh 1.10.4 20030104 b...@iname.com (Brian Hiles)
# Requires: [dc(1)], [expr(1)], ls(1), sed(1), [which(1)]
# See-also: ftp://ftp.uu.net/usenet/comp.sources.misc/volume10/stat
# See-also: ftp://ftp.uu.net/usenet/comp.sources.unix/volume18/fstat2
# See-also: http://sunsite.unc.edu/pub/Linux/utils/scripts/binstats-1.00.tgz
# See-also: kstat.ksh <jo...@armory.com> XXX
# Thanks-to: XXX <symbolic to numeric file permissions sed script>
# Usage: stat [-acfghlmrsv] file...
# Version: 1.10004

#XXX change -r option to five significant fractional digits
#XXX fails: -r option does not work with some cases: 123.0.123
#XXX to do: option to resolve full path of filename argument (for
mktag)
#XXX to do: convert "test -h" into case $... in *' -> '*) for
portability
#XXX to do: reduce extraneous calls to ls(1)
#XXX to do: new variable _link; only one while loop ls(1) ?? #XXX@
#XXX to do: how does this respond to a symlink infinite loop?
#XXX fails: stat my-symlink => _type=l but should be _type=f
#XXX to do: turn -f option into (-f num) to iterate thru num symlinks
(<=256)

#01
stat() # [-acfghlmrsv] file...
# emulate stat(2)
{ # variable side-effects: _blocks _ino _gid _mode _name _perms
# _rdev _size _time _type _uid
_day= _fall= _follow=ON _fptime= _group=ON _headers= _o= \
_pivot='[0-6][0-9]' _rc= _tab=' ' _tmopt=t _usage=\
'usage: stat [-acfghlmrsv] file...
-a - show last access time
-c - show last inode change time
-f - follow all symlinks [one only]
-g - give -g option to ls command
-h - prepend argument headers [default for multiple arguments]
-l - show stat on symlink itself
-m - show last modification time [default]
-p - perform a path lookup on the file argument
-r - show time as a floating point number, if possible
-s - do not output, only set variables
-v - verbose output'
while getopts :acFfGgHhLlmPpRrSsVvy: _inst
do case $_inst in
a) _tmopt=u ;;
c) _tmopt=c ;;
f) _fall=ON ;; # follow all symlink chains?
+f|F) _fall= ;; # follow symlink once only
g) _group=ON ;; # "ls -g" includes group info?
+g|G) _group= ;;
h) _headers=ON ;;
+h|H) _headers=OFF ;;
l) _follow= ;;
+l|L) _follow=ON ;;
m) _tmopt=t ;;
p) _pathlu=ON ;;
+p|P) _pathlu= ;;
r) _fptime=ON ;;
+r|R) _fptime= ;;
s) _silent=ON ;;
+s|S) _silent= ;;
v) _o=ON ;;
+v|V) _o= ;;
y) _pivot=$OPTARG ;; # undocumented
[?:]) echo "$_usage" >&2
return 2 ;;
esac
done
set X ${1+"$@"}; shift $OPTIND # do: shift `expr 0$OPTIND - 1`
if test X$_headers = XOFF
then _headers=
else test 0$# -gt 1 && _headers=ON
fi
_Jan=1 _Feb=2 _Mar=3 _Apr=4 _May=5 _Jun=6 _Jul=7 _Aug=8 \
_Sep=9 _Oct=10 _Nov=11 _Dec=12 _oifs=$IFS _opath=$PATH
IFS=' ' PATH=/bin${PATH:+:$PATH} # SunOS 4.x: use /usr/5bin/ls
# find current date having four digit year
eval ` date '+_curry=%Y _currm=%m _currd=%d' 2>/dev/null ||
date '+_curry=%y _currm=%m _currd=%d'
`
eval "case \$_curry in # default '69 pivot year
????) ;;
$_pivot)_curry=20\$_curry ;;
??) _curry=19\$_curry ;;
esac"
for _inst in "$@"
do _origarg=$_inst
test X$_pathlu = XON &&
if set -- ` which $_inst 2>&1 ` # SunOS which(1) rc bug
case $1 in
"no $1 in "*)
echo >&2 \
"stat: error: cannot find \"$_inst\" in path"
continue ;;
/*) _inst=$1
test -f $_inst ;;
esac
then :
else echo error: $_inst: not in path >&2
_rc="X $_rc" continue
fi
set -- X "$_inst"; shift
_blocks= _fraction= _gid= _ino= _mode= \
_name= _rdev= _size= _time= _type= _uid=
test X$_follow = XON &&
while (test -L "$1" 2>/dev/null || test -h "$1")
do set X ` BLOCKSIZE=512 LANG=C LC_ALL=C LC_TIME=C \
\ls -dl -- "$1" 2>&-
`; shift
eval "${DIAG:+echo >/dev/tty 'symlink-indirection: \"$1\"'}"
# workaround for SunOS ls(1) bug: returns 0 on EACCESS!
test 0$# -eq 0 && _rc="X $_rc" continue 2
eval "set X \${1+\"\$@\"}; shift $#"
test X$_fall = X && break # one level only?
done
# $1 now is the [symlink indirection] of argument
if set X ` BLOCKSIZE=512 LANG=C LC_ALL=C LC_TIME=C \
\ls -idls$_tmopt${_group:+g} -- "$1" 2>&-
`; shift
# SunOS ls(1) rc bug: returns 0 on EACCESS!
test 0$# -ne 0
then _ino=$1 _blocks=$2 _mode=$3 _perms=$3 _nlinks=$4 \
_uid=$5 shift 5
else echo "stat: error: cannot stat \"$_origarg\"" >&2
_rc="X $_rc" continue
fi
# set variables _mode, _perms, and _type:
eval ` echo "$_perms" | sed \
-e 's/.\(..\(.\)..\(.\)..\(.\)\).*/\2\3\4\1/
h; s/[a-z]/9/g; x; s/[STst]/9/g; G
s/\(...\).*\n...\(.*\)/\1\2/; s/[^9]/8/g
: loop
s/$/;88808891898289939884989599869997/
s/^\([0-7]*\)\(...\)\(.*\);.*\2\(.\).*/\1\4\3/
/;/!b loop' \
-e "s/;.*//; s/^/_perms=$_perms _mode=/
s/^_perms=\\(.\\)/_type=\\1 _perms=/
s/^_type=- /_type=f /"
`
# is the group field included in the ls(1) output?
case $#$_type in [79][bc]|[68][!bc]) _gid=$1 shift ;; esac
case $_type in # block or char special device?
[bc]) _size=0 _rdev=$1$2 shift 2 ;;
*) _size=$1 shift ;;
esac
case $3 in # which field: year or time?
*:*) _year=$_curry
test X$_fptime = XON && _fraction=`
IFS=:
set -- $3
test 0$# -eq 2 &&
# Bug! 0.12345 needs the leading zero truncated
echo "5k$1 60*$2+1440/ps." | dc
` ;;
*) _year=$3 ;;
esac
eval _month=\$_$1 _day=\$2 # convert month name to number
case $_month in ?) _month=0$_month; esac
# if filemonth > currentmonth then it must be for previous year
test 0$_month -gt 0$_currm && _year=` expr $_year - 1 `
case $_day in ?) _day=0$_day; esac
_time=$_year-$_month-$_day$_fraction shift 3 #XXX 0.12345
if test "X$2" = 'X->'
then _name=$1
else _name=$* # _attempt_ filenames w/ spaces
fi
# quote filenames with embedded operators or globbing-chars
# an embedded single quote will still break the output
case $_name$_origarg in *['"$&()*;<>?[|']*)_q=\';;*)_q=;;esac
test "X$_silent" = X &&
echo "${_headers:+$_q$_origarg$_q:$_tab}${_o:+type=}$_type" \
"${_o:+inode=}$_ino ${_o:+mode=}$_mode ${_o:+nlinks=}$_nlinks" \
"${_o:+uid=}$_uid ${_o:+gid=}$_gid ${_o:+size=}$_size" \
"${_o:+blocks=}$_blocks ${_o:+time=}$_time" \
"${_rdev:+ ${_o:+rdev=}$_rdev}${_o:+name=}$_q$_name$_q" # <=TAB
done
set X $_rc; shift # retval is num of args in err
unset _Jan _Feb _Mar _Apr _May _Jun _Jul _Aug _Sep _Oct _Nov _Dec
unset _day _fall _follow _fptime _fraction _group _headers _ls _month
unset _o _origarg _q _rc _silent _tab _tmopt _usage _year #_inst
eval "unset _oifs _opath; IFS='$_oifs' PATH='$_opath' return $#"
}

#02 EMBEDDED MANPAGE FOR "src2man"
: '
!++
NAME
stat -- shell emulation of stat(3)/lstat(3)

SYNOPSIS
stat [-acfghlmrsv] file...

OPTIONS
-a - show last access time.
-c - show last inode change time.
-f - follow all symlinks [one only].
-g - give -g option to ls command.
-h - prepend argument headers [default for multiple arguments].
-l - show stat on symlink itself.
-m - show last modification time [default].
-r - show time as a floating point number, if possible.
-s - do not output, only set variables.
-v - verbose output.

DESCRIPTION
Function stat(3S) emulates stat(3) and lstat(3). The -l option will
stat the inode which represents the symbolic link, just as lstat(3)
does. The -a, -c, and -m options show the access, inode change/
create,
and modification times, respectively.

Unlike stat(3), additional options are available as befitting the
high-level nature of shell: the -f option is a directive to follow
all symbolic links, if there are multiple indirections; the -r option
may be used to allow the three times to be in the form of a floating
point number.

Use option -h to necessarily prepend headers of the original
parameter;
option -v will output in the form of a variable assignment list.
Conversely, use option -s to only set, not display, the variables
_blocks, _gid, _ino, _mode, _nlinks, _rdev, _size, _time, and _uid
(corresponding to the structure "stat" fields declared in <sys/
stat.h>)
as well as _name, _perms, and _type variables. _type takes the values
[fbcdlps] to mean the argument is a plain file, block-special file,
character-special file, directory, symbolic link, named pipe, or
socket. _blocks is expressed in multiples of 512 bytes, and as such
does not technically reflect the st_size field in structure stat(3)
because the block-size for the file-system of that file may be a
different value. Variable _perms holds the symbolic permissions field
as accepted by chmod(1). There is no analogue for the stat(3) field
st_dev.

Read the CAVEATS section for a discussion for the necessity of the
-g option.

RETURN VALUE
Returns 0 if successful, 2 for options parsing errors, otherwise
the number of arguments in error.

AUTHOR
Brian Hiles <b...@iname.com>

SEE ALSO
resolvepath(3S)

NOTES
Date output format conforms to ISO-8601. #XXX

This function makes side-effects upon the variables _blocks, _ino,
_gid, _mode, _name, _perms, _rdev, _size, _time, _type, and _uid.

In sh(1), a handy idiom to do word splitting upon (for example)
$_time, given a character (for example) "-", is:

eval "IFS=-; set -- \$_time; IFS='$IFS'"

$1 will now hold the year, $2 the month, and $3 the day. This can
also be used for separating directory components in a path. Variable
IFS (which cannot contain a single-quote) will not be modified.

A general method to do field-splitting upon the output of stat(3S)
is:

eval ` stat -v file `

But it is more efficient to use the -s option and directly use the
side-effect variables listed above.

CAVEATS
The output format of the ls(1) command is different, sometimes for
the same option, between the System V and BSD derived
implementations.
Regarding the inclusion of a -g option, for BSD ls(1) the group field
is printed, otherwise it not; for System V ls(1), the group field
replaces the owner field, otherwise both are printed. There is no
robust and portable method of determining the difference: either the
-g or -G option to stat(3S) may need to be specified or not depending
on either behavior.

The name and group fields may be either a name or a number; it
depends
how the underlying ls(1) resolves uid and/or gid information.

With the -r option, the precision of the floating-point date/time
number is better than for a granularity of one second; however, the
granularity of the ls(1) time field is to the nearest minute. XXX

BUGS
Only when the file is less than six months old will the timestamp
(access-, create-, or mod-time) information be available to calculate
a floating point remainder of a day when given the -r option.

This function is broken by filenames with leading/following and/or
two or more sequential embedded space characters.

Limitations and caveats for the stat(3S) function are the same as
for ls(1), as this function is effectively a parser built over it.

Too heavyweight: ls(1) is executed at least twice for each file
argument, and additionally up to 257 times to potentially resolve
a symlink!

!--
'

Kees Nuyt

unread,
Dec 16, 2011, 7:10:35 PM12/16/11
to
On Fri, 16 Dec 2011 02:42:46 -0500, Barry Margolin
<bar...@alum.mit.edu> wrote:

>In article
><5f9d0ee3-7fcf-497c...@r16g2000prr.googlegroups.com>,
> bsh <brian...@rocketmail.com> wrote:
>
>> It's even a bit more complicated than that, insofar as the number of
>> ls(1)
>> fields will vary if the create/access/modify time of the given
>> filename is newer
>> than a certain internally defined period.
>
>No it doesn't. It's either "Mon Day Time" or "Month Day Year", but
>either way it's the same number of fields. I expect this was by design.
>
>However, if the filename contains whitespace, that will mess up column
>counting.

/me loves ls -E (AKA --full-time )
Best regards,
--
( Kees Nuyt
)
c[_]

Barry Margolin

unread,
Dec 16, 2011, 7:27:05 PM12/16/11
to
In article
<1aabacd6-e593-4b9f...@s10g2000prs.googlegroups.com>,
I was responding to a specific point about the output of ls(1), not the
general issue. You said that the number of fields will vary based on
the timestamp. While there are reasons that the number of fields will
vary (specifially, whitespace in the filename), the timestamp is not
such a reason.

So your script may be useful, but not for the reason of timestamps.

bsh

unread,
Dec 16, 2011, 7:51:16 PM12/16/11
to
Barry Margolin <bar...@alum.mit.edu> wrote:
> bsh <brian_hi...@rocketmail.com> wrote:
> > Barry Margolin <bar...@alum.mit.edu> wrote:
> > > bsh <brian_hi...@rocketmail.com> wrote:
> > > > ...
> I was responding to a specific point about the output of ls(1), not the
> general issue.  You said that the number of fields will vary based on
> the timestamp.  While there are reasons that the number of fields will
> vary (specifially, whitespace in the filename), the timestamp is not
> such a reason.

I understand the constraints for the context of the reply,
but not why the timestamp, being the formatted string as
described in the ls(1) output, is not the applicable issue as
described by my reply and script.

> So your script may be useful, but not for the reason of timestamps.

Huh?

=Brian

Barry Margolin

unread,
Dec 16, 2011, 8:57:18 PM12/16/11
to
In article
<8dbed9ce-ef56-45ef...@c16g2000pre.googlegroups.com>,
bsh <brian...@rocketmail.com> wrote:

> Barry Margolin <bar...@alum.mit.edu> wrote:
> > bsh <brian_hi...@rocketmail.com> wrote:
> > > Barry Margolin <bar...@alum.mit.edu> wrote:
> > > > bsh <brian_hi...@rocketmail.com> wrote:
> > > > > ...
> > I was responding to a specific point about the output of ls(1), not the
> > general issue.  You said that the number of fields will vary based on
> > the timestamp.  While there are reasons that the number of fields will
> > vary (specifially, whitespace in the filename), the timestamp is not
> > such a reason.
>
> I understand the constraints for the context of the reply,
> but not why the timestamp, being the formatted string as
> described in the ls(1) output, is not the applicable issue as
> described by my reply and script.

Because the number of fields in the timestamp doesn't vary. If the
timestamp is within 6 months of the current time, it's displayed as "MMM
DD HH:MM". If it's outside this range it's "MMM DD YYYY". Either way,
it's 3 fields. Here's an example from my machine, showing the newest
and oldest items in my directory:

imac:barmar $ ls -lt | head -2 | tail -1
drwxr-xr-x@ 5 barmar barmar 170 Dec 16 04:41 Desktop
imac:barmar $ ls -lt | tail -1
-rw-r--r-- 1 barmar barmar 69464 Mar 31 2003 symbol.ttf

The timestamps line up exactly with each other. There's even an extra
space before the year so that the character position of the beginning of
the filename is always the same (but I think this can be upset if the
size of a file gets too large).

Bill Marcum

unread,
Dec 16, 2011, 6:15:50 PM12/16/11
to
On 2011-12-16, Timothy Madden <termin...@gmail.com> wrote:
>
> To be correct, I can not see /any/ possible case where this substitution
> would fail to return the actual file being linked.
>
Unless the link name or file name contains the characters '->'

--
We've had 30 years of center-right to extreme-right governance and the
country has gotten steadily worse. The triumph of politics is that at
least half the country blames the Democrats for this.

Ben Bacarisse

unread,
Dec 17, 2011, 3:22:54 PM12/17/11
to
Bill Marcum <bi...@lat.localnet> writes:

> On 2011-12-16, Timothy Madden <termin...@gmail.com> wrote:
>>
>> To be correct, I can not see /any/ possible case where this substitution
>> would fail to return the actual file being linked.
>>
> Unless the link name or file name contains the characters '->'

You clipped the context of this remark. It's about this code:

${ls_output#*"${link_name} -> "}

which works when either or both the link name or file name contain '->'.
More to the point it works when either or both includes ' -> ' (unless
I'm missing something here).

--
Ben.

Geoff Clare

unread,
Dec 19, 2011, 8:27:00 AM12/19/11
to
Barry Margolin wrote:

> Because the number of fields in the timestamp doesn't vary. If the
> timestamp is within 6 months of the current time, it's displayed as "MMM
> DD HH:MM". If it's outside this range it's "MMM DD YYYY". Either way,
> it's 3 fields. Here's an example from my machine, showing the newest
> and oldest items in my directory:
>
> imac:barmar $ ls -lt | head -2 | tail -1
> drwxr-xr-x@ 5 barmar barmar 170 Dec 16 04:41 Desktop
> imac:barmar $ ls -lt | tail -1
> -rw-r--r-- 1 barmar barmar 69464 Mar 31 2003 symbol.ttf

If you need to rely on this, you should force the use of the C locale.
The number of fields can be different in other locales:

$ LC_TIME=C ls -ld /
drwxr-xr-x 28 root root 4096 Jan 26 2010 /
$ LC_TIME=en_GB ls -ld /
drwxr-xr-x 28 root root 4096 2010-01-26 14:32 /

--
Geoff Clare <net...@gclare.org.uk>

Janis Papanagnou

unread,
Dec 19, 2011, 10:48:59 AM12/19/11
to
Am 19.12.2011 14:27, schrieb Geoff Clare:
> Barry Margolin wrote:
>
>> Because the number of fields in the timestamp doesn't vary. If the
>> timestamp is within 6 months of the current time, it's displayed as "MMM
>> DD HH:MM". If it's outside this range it's "MMM DD YYYY". Either way,
>> it's 3 fields. Here's an example from my machine, showing the newest
>> and oldest items in my directory:
>>
>> imac:barmar $ ls -lt | head -2 | tail -1
>> drwxr-xr-x@ 5 barmar barmar 170 Dec 16 04:41 Desktop
>> imac:barmar $ ls -lt | tail -1
>> -rw-r--r-- 1 barmar barmar 69464 Mar 31 2003 symbol.ttf
>
> If you need to rely on this, you should force the use of the C locale.
> The number of fields can be different in other locales:

Rely on the C locale? - Hmm..

>
> $ LC_TIME=C ls -ld /
> drwxr-xr-x 28 root root 4096 Jan 26 2010 /
> $ LC_TIME=en_GB ls -ld /
> drwxr-xr-x 28 root root 4096 2010-01-26 14:32 /
>

I'd select one with a format I can rely on without necessity to handle
edge cases with files newer/older than six months and with this
non-regular and harder to parse US format that the C locale supports.

Janis

Kees Nuyt

unread,
Dec 19, 2011, 2:11:10 PM12/19/11
to
Hm, not for me

$ LC_TIME=en_GB /usr/xpg4/bin/ls -ld /
drwxr-xr-x 26 root root 27 Dec 17 12:31 /

$ LC_TIME=en_GB /usr/bin/ls -ld /
drwxr-xr-x 26 root root 27 Dec 17 12:31 /

$ uname -a
SunOS ozon 5.11 snv_130 i86pc i386 i86pc

$ which ls
/usr/xpg4/bin/ls

$ /usr/xpg4/bin/ls -ld /
drwxr-xr-x 26 root root 27 Dec 17 12:31 /

Luckily, POSIX has option E :

$ /usr/xpg4/bin/ls -Ed /
drwxr-xr-x 26 root root 27 2011-12-17 12:31:16.958586777 +0100 /

$ /usr/xpg4/bin/ls -ld --full-time /
drwxr-xr-x 26 root root 27 2011-12-17 12:31:16.958586777 +0100 /

man ls :
:
:
-E
The same as -l, except displays time to the nanosecond
and with one format for all files regardless of age:

yyyy-mm-dd hh:mm:ss.nnnnnnnnn (ISO 8601:2000 format).

In addition, this option displays the offset from UTC in
ISO 8601:2000 standard format (+hhmm or -hhmm) or no
characters if the offset is indeterminable. The offset
reflects the appropriate standard or alternate offset in
force at the file's displayed date and time, under the
current timezone.
:
:

pk

unread,
Dec 20, 2011, 3:49:40 AM12/20/11
to
On Mon, 19 Dec 2011 20:11:10 +0100, Kees Nuyt <k.n...@nospam.demon.nl>
wrote:

> Luckily, POSIX has option E :
>
> $ /usr/xpg4/bin/ls -Ed /
> drwxr-xr-x 26 root root 27 2011-12-17 12:31:16.958586777 +0100 /
>
> $ /usr/xpg4/bin/ls -ld --full-time /
> drwxr-xr-x 26 root root 27 2011-12-17 12:31:16.958586777 +0100 /
>
> man ls :
> :
> :
> -E
> The same as -l, except displays time to the nanosecond
> and with one format for all files regardless of age:
>
> yyyy-mm-dd hh:mm:ss.nnnnnnnnn (ISO 8601:2000 format).
>
> In addition, this option displays the offset from UTC in
> ISO 8601:2000 standard format (+hhmm or -hhmm) or no
> characters if the offset is indeterminable. The offset
> reflects the appropriate standard or alternate offset in
> force at the file's displayed date and time, under the
> current timezone.
> :
> :

Certainly useful, but doesn't seem to be POSIX.

0 new messages