zsh-users
 help / color / mirror / code / Atom feed
* Equivalent of set -- *(DN) in sh
@ 2015-01-18 18:28 Nikolai Weibull
  2015-01-18 19:07 ` Roman Neuhauser
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Nikolai Weibull @ 2015-01-18 18:28 UTC (permalink / raw)
  To: Zsh Users

Hi!

Is there any way to get the equivalent of Zsh’s

set -- *(DN)

in sh?  Most important here would be NULL_GLOB, as, by default, sh
simply leaves the * if there are no files to match.

Thanks!


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 18:28 Equivalent of set -- *(DN) in sh Nikolai Weibull
@ 2015-01-18 19:07 ` Roman Neuhauser
  2015-01-18 19:43   ` Nikolai Weibull
  2015-01-18 19:31 ` ZyX
  2015-01-18 20:46 ` Eric Cook
  2 siblings, 1 reply; 15+ messages in thread
From: Roman Neuhauser @ 2015-01-18 19:07 UTC (permalink / raw)
  To: Nikolai Weibull; +Cc: Zsh Users

# now@disu.se / 2015-01-18 19:28:42 +0100:
> Is there any way to get the equivalent of Zsh´s
> 
> set -- *(DN)
> 
> in sh?  Most important here would be NULL_GLOB, as, by default, sh
> simply leaves the * if there are no files to match.

set -- $(find .* * -maxdepth 0 -type d)

does not handle names with spaces.

-- 
roman


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 18:28 Equivalent of set -- *(DN) in sh Nikolai Weibull
  2015-01-18 19:07 ` Roman Neuhauser
@ 2015-01-18 19:31 ` ZyX
  2015-01-18 19:46   ` Nikolai Weibull
  2015-01-18 20:46 ` Eric Cook
  2 siblings, 1 reply; 15+ messages in thread
From: ZyX @ 2015-01-18 19:31 UTC (permalink / raw)
  To: Nikolai Weibull, Zsh Users

18.01.2015, 21:36, "Nikolai Weibull" <now@disu.se>:
> Hi!
>
> Is there any way to get the equivalent of Zsh’s
>
> set -- *(DN)
>
> in sh?  Most important here would be NULL_GLOB, as, by default, sh
> simply leaves the * if there are no files to match.
>
> Thanks!

If you are OK with bash then you may use `shopt -s nullglob; shopt -s dotglob` and use `set -- *`. Note that solution posted by Roman Neuhauser does handle names with spaces and tabs, but not newlines, if you set $IFS to a newline. As-is it has problems with all characters in IFS which are not just space, but also tab and newline.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 19:07 ` Roman Neuhauser
@ 2015-01-18 19:43   ` Nikolai Weibull
  2015-01-18 20:32     ` Roman Neuhauser
  0 siblings, 1 reply; 15+ messages in thread
From: Nikolai Weibull @ 2015-01-18 19:43 UTC (permalink / raw)
  To: Roman Neuhauser; +Cc: Zsh Users

On Sun, Jan 18, 2015 at 8:07 PM, Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
> # now@disu.se / 2015-01-18 19:28:42 +0100:
>> Is there any way to get the equivalent of Zsh´s
>>
>> set -- *(DN)
>>
>> in sh?  Most important here would be NULL_GLOB, as, by default, sh
>> simply leaves the * if there are no files to match.
>
> set -- $(find .* * -maxdepth 0 -type d)
>
> does not handle names with spaces.

Which is unsatisfactory, as $() isn’t in all versions of sh, -maxdepth
is GNU specific, and .* and * will be expanded by the shell, not by
find, so we’ve gained nothing and lost quite a bit.  Oh, and who said
anything about only including directories?  ;-)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 19:31 ` ZyX
@ 2015-01-18 19:46   ` Nikolai Weibull
  0 siblings, 0 replies; 15+ messages in thread
From: Nikolai Weibull @ 2015-01-18 19:46 UTC (permalink / raw)
  To: ZyX; +Cc: Zsh Users

On Sun, Jan 18, 2015 at 8:31 PM, ZyX <kp-pav@yandex.ru> wrote:
> 18.01.2015, 21:36, "Nikolai Weibull" <now@disu.se>:

>> Is there any way to get the equivalent of Zsh’s
>>
>> set -- *(DN)
>>
>> in sh?  Most important here would be NULL_GLOB, as, by default, sh
>> simply leaves the * if there are no files to match.

> If you are OK with bash then you may use `shopt -s nullglob; shopt -s dotglob` and use `set -- *`.

I’m not.  Depending on Bash is like depending on Zsh these days, I’d
say, in terms of availability.

> Note that solution posted by Roman Neuhauser does handle names with spaces and tabs, but not newlines, if you set $IFS to a newline. As-is it has problems with all characters in IFS which are not just space, but also tab and newline.

The solution has to be functionally equivalent.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 19:43   ` Nikolai Weibull
@ 2015-01-18 20:32     ` Roman Neuhauser
  0 siblings, 0 replies; 15+ messages in thread
From: Roman Neuhauser @ 2015-01-18 20:32 UTC (permalink / raw)
  To: Nikolai Weibull; +Cc: Zsh Users

# now@disu.se / 2015-01-18 20:43:55 +0100:
> On Sun, Jan 18, 2015 at 8:07 PM, Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
> > # now@disu.se / 2015-01-18 19:28:42 +0100:
> >> Is there any way to get the equivalent of Zsh´s
> >>
> >> set -- *(DN)
> >>
> >> in sh?  Most important here would be NULL_GLOB, as, by default, sh
> >> simply leaves the * if there are no files to match.
> >
> > set -- $(find .* * -maxdepth 0 -type d)
> >
> > does not handle names with spaces.
> 
> Which is unsatisfactory, as $() isn´t in all versions of sh,

then use `find ...`, problem solved.

btw if your requirements are this stringent you would have done well
if you laid them out upfront.

> -maxdepth is GNU specific

it's not, at least all BSDs have it as well.  again, what operating
systems do you need to support?

> and .* and * will be expanded by the shell, not by find

you can `find . -maxdepth 1 -mindepth 1`, but the paths will be prefixed
with "./".  you could of ocurse append `| sed 's:..::'`.

OTOH, what's the problem with the shell expanding the globs?
if .* or * does not exist, sh leaves that there as-is, find cannot
chdir into it, and definitely won't print it.

> Oh, and who said anything about only including directories?  ;-)

yeah, that was a brainfart, sorry.

-- 
roman


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 18:28 Equivalent of set -- *(DN) in sh Nikolai Weibull
  2015-01-18 19:07 ` Roman Neuhauser
  2015-01-18 19:31 ` ZyX
@ 2015-01-18 20:46 ` Eric Cook
  2015-01-19 15:51   ` ZyX
  2 siblings, 1 reply; 15+ messages in thread
From: Eric Cook @ 2015-01-18 20:46 UTC (permalink / raw)
  To: zsh-users

On 01/18/2015 01:28 PM, Nikolai Weibull wrote:
> Hi!
>
> Is there any way to get the equivalent of Zsh’s
>
> set -- *(DN)
>
> in sh?  Most important here would be NULL_GLOB, as, by default, sh
> simply leaves the * if there are no files to match.
>
> Thanks!

match() {
  test "$#" -gt 2 && return
  test -e "$1"    && return
  return 1
}

set --
for pat in '.[^.]*' '*'; do # *(DN) ignores . and ..
  if match $pat; then
    set -- "$@" $pat
  fi
done
unset pat

test "$#" -gt 0 && printf '%s\n' "$@"



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-18 20:46 ` Eric Cook
@ 2015-01-19 15:51   ` ZyX
  2015-01-19 15:55     ` ZyX
                       ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: ZyX @ 2015-01-19 15:51 UTC (permalink / raw)
  To: Eric Cook, zsh-users


18.01.2015, 23:53, "Eric Cook" <llua@gmx.com>:
> On 01/18/2015 01:28 PM, Nikolai Weibull wrote:
>>  Hi!
>>
>>  Is there any way to get the equivalent of Zsh’s
>>
>>  set -- *(DN)
>>
>>  in sh?  Most important here would be NULL_GLOB, as, by default, sh
>>  simply leaves the * if there are no files to match.
>>
>>  Thanks!
>
> match() {
>   test "$#" -gt 2 && return
>   test -e "$1"    && return
>   return 1
> }
>
> set --
> for pat in '.[^.]*' '*'; do # *(DN) ignores . and ..

`..foo` is a valid name, but it is being excluded. You need to add `'.??*'` to the list of patterns.

>   if match $pat; then
>     set -- "$@" $pat
>   fi
> done
> unset pat
>
> test "$#" -gt 0 && printf '%s\n' "$@"


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-19 15:51   ` ZyX
@ 2015-01-19 15:55     ` ZyX
  2015-01-19 16:02       ` ZyX
  2015-01-19 21:44     ` Eric Cook
       [not found]     ` <54BD7ABB.5070501__36205.2317861982$1421704010$gmane$org@gmx.com>
  2 siblings, 1 reply; 15+ messages in thread
From: ZyX @ 2015-01-19 15:55 UTC (permalink / raw)
  To: Eric Cook, zsh-users



19.01.2015, 18:51, "ZyX" <kp-pav@yandex.ru>:
> 18.01.2015, 23:53, "Eric Cook" <llua@gmx.com>:
>>  On 01/18/2015 01:28 PM, Nikolai Weibull wrote:
>>>   Hi!
>>>
>>>   Is there any way to get the equivalent of Zsh’s
>>>
>>>   set -- *(DN)
>>>
>>>   in sh?  Most important here would be NULL_GLOB, as, by default, sh
>>>   simply leaves the * if there are no files to match.
>>>
>>>   Thanks!
>>  match() {
>>    test "$#" -gt 2 && return
>>    test -e "$1"    && return
>>    return 1
>>  }
>>
>>  set --
>>  for pat in '.[^.]*' '*'; do # *(DN) ignores . and ..
>
> `..foo` is a valid name, but it is being excluded. You need to add `'.??*'` to the list of patterns.

No, this may make duplicates. Then `'..?*'`.

>>    if match $pat; then
>>      set -- "$@" $pat
>>    fi
>>  done
>>  unset pat
>>
>>  test "$#" -gt 0 && printf '%s\n' "$@"


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-19 15:55     ` ZyX
@ 2015-01-19 16:02       ` ZyX
  2015-01-19 16:16         ` ZyX
  0 siblings, 1 reply; 15+ messages in thread
From: ZyX @ 2015-01-19 16:02 UTC (permalink / raw)
  To: Eric Cook, zsh-users


19.01.2015, 18:55, "ZyX" <kp-pav@yandex.ru>:
> 19.01.2015, 18:51, "ZyX" <kp-pav@yandex.ru>:
>>  18.01.2015, 23:53, "Eric Cook" <llua@gmx.com>:
>>>   On 01/18/2015 01:28 PM, Nikolai Weibull wrote:
>>>>    Hi!
>>>>
>>>>    Is there any way to get the equivalent of Zsh’s
>>>>
>>>>    set -- *(DN)
>>>>
>>>>    in sh?  Most important here would be NULL_GLOB, as, by default, sh
>>>>    simply leaves the * if there are no files to match.
>>>>
>>>>    Thanks!
>>>   match() {
>>>     test "$#" -gt 2 && return
>>>     test -e "$1"    && return
>>>     return 1
>>>   }
>>>
>>>   set --
>>>   for pat in '.[^.]*' '*'; do # *(DN) ignores . and ..
>>  `..foo` is a valid name, but it is being excluded. You need to add `'.??*'` to the list of patterns.
>
> No, this may make duplicates. Then `'..?*'`.

And you must replace `[^.]` with `[!.]`. mksh does not support `[^]` and treats this as `[\^.]`, but other shells I have (dash, ksh, zsh (in sh emulation mode), bash, busybox ash) are fine with both `[!.]` and `[^.]`.

>>>     if match $pat; then
>>>       set -- "$@" $pat
>>>     fi
>>>   done
>>>   unset pat
>>>
>>>   test "$#" -gt 0 && printf '%s\n' "$@"


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-19 16:02       ` ZyX
@ 2015-01-19 16:16         ` ZyX
  0 siblings, 0 replies; 15+ messages in thread
From: ZyX @ 2015-01-19 16:16 UTC (permalink / raw)
  To: Eric Cook, zsh-users



19.01.2015, 19:02, "ZyX" <kp-pav@yandex.ru>:
> 19.01.2015, 18:55, "ZyX" <kp-pav@yandex.ru>:
>>  19.01.2015, 18:51, "ZyX" <kp-pav@yandex.ru>:
>>>   18.01.2015, 23:53, "Eric Cook" <llua@gmx.com>:
>>>>    On 01/18/2015 01:28 PM, Nikolai Weibull wrote:
>>>>>     Hi!
>>>>>
>>>>>     Is there any way to get the equivalent of Zsh’s
>>>>>
>>>>>     set -- *(DN)
>>>>>
>>>>>     in sh?  Most important here would be NULL_GLOB, as, by default, sh
>>>>>     simply leaves the * if there are no files to match.
>>>>>
>>>>>     Thanks!
>>>>    match() {
>>>>      test "$#" -gt 2 && return
>>>>      test -e "$1"    && return
>>>>      return 1
>>>>    }
>>>>
>>>>    set --
>>>>    for pat in '.[^.]*' '*'; do # *(DN) ignores . and ..
>>>   `..foo` is a valid name, but it is being excluded. You need to add `'.??*'` to the list of patterns.
>>  No, this may make duplicates. Then `'..?*'`.
>
> And you must replace `[^.]` with `[!.]`. mksh does not support `[^]` and treats this as `[\^.]`, but other shells I have (dash, ksh, zsh (in sh emulation mode), bash, busybox ash) are fine with both `[!.]` and `[^.]`.
>>>>      if match $pat; then
>>>>        set -- "$@" $pat
>>>>      fi
>>>>    done
>>>>    unset pat
>>>>
>>>>    test "$#" -gt 0 && printf '%s\n' "$@"

Also note that if you need *full* equivalent of *(DN) you need to do something with ordering. I have checked all the shells with

    for sh in dash ksh mksh zsh bash bb ; do $sh set--sDN.sh > set--sDN.$sh.log ; done

with

    emulate -L sh &>/dev/null
    match() {
      test "$#" -gt 2 && return
      test -e "$1"    && return
      return 1
    }
    
    set --
    for pat in '.[!.]*' '..?*' '*'; do # *(DN) ignores . and ..
      if match $pat; then
        set -- "$@" $pat
      fi
    done
    unset pat
    
    test "$#" -gt 0 && printf '>>%s<<\n' "$@"

in set--sDN.sh file and have the following md5sums:

    % md5sum set--sDN.*.log | sort
    4601e6d9c845fe88e5166db3be04cc75  set--sDN.bash.log
    4601e6d9c845fe88e5166db3be04cc75  set--sDN.ksh.log
    4601e6d9c845fe88e5166db3be04cc75  set--sDN.zsh.log
    ac2c245cdac664121a348c6b05ea2f44  set--sDN.bb.log
    ac2c245cdac664121a348c6b05ea2f44  set--sDN.dash.log
    ac2c245cdac664121a348c6b05ea2f44  set--sDN.mksh.log

: two variants of ordering:

bash/ksh/zsh:

    >>.abc<<
    >>.b<<
    >>.^foo<<
    >>..foo<<
    >>
    <<
    >>1<<
    >>17<<
    >>2<<
    >>append-remove.bash<<
    >>getnumbers.bash<<
    >>grepdir<<
    >>nroff<<
    >>parinput.bash<<
    >>qwerty<<
    >>rl.sh<<
    >>script_path.bash<<
    >>set--sDN.bash.log<<
    >>set--sDN.bb.log<<
    >>set--sDN.dash.log<<
    >>set--sDN.ksh.log<<
    >>set--sDN.mksh.log<<
    >>set--sDN.sh<<
    >>set--sDN.zsh.log<<
    >>tes.bash<<
    >>test<<
    >>test2.bash<<
    >>test3.bash<<
    >>test.bash<<
    >>testdir<<
    >>test-rename.sh<<
    >>test-so-2914220.bash<<
    >>t.tar<<
    >>ttttt.tar.bz2<<
    >>ttttt.tar.gz<<

bb/dash/mksh:

    >>.^foo<<
    >>.abc<<
    >>.b<<
    >>..foo<<
    >>
    <<
    >>1<<
    >>17<<
    >>2<<
    >>append-remove.bash<<
    >>getnumbers.bash<<
    >>grepdir<<
    >>nroff<<
    >>parinput.bash<<
    >>qwerty<<
    >>rl.sh<<
    >>script_path.bash<<
    >>set--sDN.bash.log<<
    >>set--sDN.bb.log<<
    >>set--sDN.dash.log<<
    >>set--sDN.ksh.log<<
    >>set--sDN.mksh.log<<
    >>set--sDN.sh<<
    >>set--sDN.zsh.log<<
    >>t.tar<<
    >>tes.bash<<
    >>test<<
    >>test-rename.sh<<
    >>test-so-2914220.bash<<
    >>test.bash<<
    >>test2.bash<<
    >>test3.bash<<
    >>testdir<<
    >>ttttt.tar.bz2<<
    >>ttttt.tar.gz<<

(note position of t.tar).

I have verified that all tests emit essentially the same result by using `for f in set--sDN.*.log ; do cat $f | sort | md5sum ; done | uniq`. But both orderings are different from the zsh one:

    % zsh -f -c 'for f in *(DN); do echo ">>$f<<" ; done'
    >>
    <<
    >>1<<
    >>17<<
    >>2<<
    >>.abc<<
    >>append-remove.bash<<
    >>.b<<
    >>.^foo<<
    >>..foo<<
    >>getnumbers.bash<<
    >>grepdir<<
    >>nroff<<
    >>parinput.bash<<
    >>qwerty<<
    >>rl.sh<<
    >>script_path.bash<<
    >>set--sDN.bash.log<<
    >>set--sDN.bb.log<<
    >>set--sDN.dash.log<<
    >>set--sDN.ksh.log<<
    >>set--sDN.mksh.log<<
    >>set--sDN.sh<<
    >>set--sDN.zsh.log<<
    >>tes.bash<<
    >>test<<
    >>test2.bash<<
    >>test3.bash<<
    >>test.bash<<
    >>testdir<<
    >>test-rename.sh<<
    >>test-so-2914220.bash<<
    >>t.tar<<
    >>ttttt.tar.bz2<<
    >>ttttt.tar.gz<<

(note: I have filename with newline, this is why I added `>><<`.)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-19 15:51   ` ZyX
  2015-01-19 15:55     ` ZyX
@ 2015-01-19 21:44     ` Eric Cook
       [not found]     ` <54BD7ABB.5070501__36205.2317861982$1421704010$gmane$org@gmx.com>
  2 siblings, 0 replies; 15+ messages in thread
From: Eric Cook @ 2015-01-19 21:44 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2490 bytes --]

On 01/19/2015 10:51 AM, ZyX wrote:
> `..foo` is a valid name, but it is being excluded. You need to add `'.??*'` to the list of patterns.
Nice catch.

On 01/19/2015 11:02 AM, ZyX wrote:
>
> And you must replace `[^.]` with `[!.]`. mksh does not support `[^]` and treats this as `[\^.]`, but other shells I have (dash, ksh, zsh (in sh emulation mode), bash, busybox ash) are fine with both `[!.]` and `[^.]`.
and again.

On 01/19/2015 11:16 AM, ZyX wrote:
>     emulate -L sh &>/dev/null
While this is just an test, it should be pointed out that `&>' is also
not defined nor does the same thing in all of the shells you tried. The
correct way being `>/dev/null 2>&1'.

On 01/19/2015 11:16 AM, ZyX wrote:
> Also note that if you need *full* equivalent of *(DN) you need to do something with ordering.
That depends on the user's locale, my LC_COLLATE was set to POSIX during
my tests and each shell sorted the files the same.
Setting LC_COLLATE to en_US.UTF-8 does give me the behavior you
mentioned. I don't think there is a correct way to account for that.

With:

#!/bin/sh
${ZSH_VERSION+false} : || emulate sh
match() {
  test "$#" -gt 2 && return
  test -e "$1"    && return
  return 1
}

set --
for pat in '..?*' '.[!.]*' '*'; do # I moved your added pattern to where
POSIX locale would sort them.
  if match $pat; then
    set -- "$@" $pat
  fi
done
unset pat

test "$#" -gt 0 && printf '%s ' "$@"

% LC_COLLATE=POSIX
% printf '%s ' *(DN) > ../zshdn--set.log
% for sh in dash ksh mksh zsh bash bb; do $sh ../foo >../$sh--set.log; done
% md5sum ../*--set.log
99970f198535e5fe62aeec1a13ebc639  ../bash--set.log
99970f198535e5fe62aeec1a13ebc639  ../bb--set.log
99970f198535e5fe62aeec1a13ebc639  ../dash--set.log
99970f198535e5fe62aeec1a13ebc639  ../ksh--set.log
99970f198535e5fe62aeec1a13ebc639  ../mksh--set.log
99970f198535e5fe62aeec1a13ebc639  ../zsh--set.log
99970f198535e5fe62aeec1a13ebc639  ../zshdn--set.log


% LC_COLLATE=en_US.UTF-8
% printf '%s ' *(DN) > ../zshdn--set.log
% for sh in dash ksh mksh zsh bash bb; do $sh ../foo >../$sh--set.log; done
% md5sum ../*--set.log
28583c502cf605e105f794a37e1648da  ../bash--set.log
28583c502cf605e105f794a37e1648da  ../bb--set.log
99970f198535e5fe62aeec1a13ebc639  ../dash--set.log
28583c502cf605e105f794a37e1648da  ../ksh--set.log
99970f198535e5fe62aeec1a13ebc639  ../mksh--set.log
4008c14ae7f0b2195c96d330d604ae50  ../zshdn--set.log
28583c502cf605e105f794a37e1648da  ../zsh--set.log

Strangely, the two zsh tests i did aren't the same.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
       [not found]     ` <54BD7ABB.5070501__36205.2317861982$1421704010$gmane$org@gmx.com>
@ 2015-01-19 23:05       ` Stephane Chazelas
  2015-01-22  7:44         ` Nikolai Weibull
       [not found]         ` <CADdV=MsvuSAQMJVsr17Y7g2Nfjy95CQ007opQqv-7=RHjgjaKw__35342.9068615243$1421913204$gmane$org@mail.gmail.com>
  0 siblings, 2 replies; 15+ messages in thread
From: Stephane Chazelas @ 2015-01-19 23:05 UTC (permalink / raw)
  To: Eric Cook; +Cc: zsh-users

2015-01-19 16:44:27 -0500, Eric Cook:
[...]
> #!/bin/sh
> ${ZSH_VERSION+false} : || emulate sh
> match() {
>   test "$#" -gt 2 && return

Why not "-gt 1"?

>   test -e "$1"    && return

test -e

will return false for a symlink to an inaccessible file. So
you'll want a test -L "$1" as well.

>   return 1
> }
> 
> set --
> for pat in '..?*' '.[!.]*' '*'; do # I moved your added pattern to where
> POSIX locale would sort them.
>   if match $pat; then
>     set -- "$@" $pat

Note that for that to work in the Bourne shell, IFS needs to
contain space (and none of the characters in the patterns in all
Bourne-like shells).

Another approach that only relies on reading the directory
contents (not "stat"ing the files):

set -- [*] *
case $1$2 in
  '[*]*') shift 2;;
  *) shift
esac
IFS=" "
set -- .[.]?* ${1+"$@"}
case $1 in '.[.]?*') shift; esac
set -- .[[]'!.]?*' .[!.]?* ${1+"$@"}
case $1$2 in
  '.[[]!.]?*.[!.]?*') shift 2;;
  *) shift
esac

(won't give the same order as *(ND) either).

-- 
Stephane


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
  2015-01-19 23:05       ` Stephane Chazelas
@ 2015-01-22  7:44         ` Nikolai Weibull
       [not found]         ` <CADdV=MsvuSAQMJVsr17Y7g2Nfjy95CQ007opQqv-7=RHjgjaKw__35342.9068615243$1421913204$gmane$org@mail.gmail.com>
  1 sibling, 0 replies; 15+ messages in thread
From: Nikolai Weibull @ 2015-01-22  7:44 UTC (permalink / raw)
  To: Eric Cook, zsh-users

On Tue, Jan 20, 2015 at 12:05 AM, Stephane Chazelas
<stephane.chazelas@gmail.com> wrote:

> Another approach that only relies on reading the directory
> contents (not "stat"ing the files):
>
> set -- [*] *
> case $1$2 in
>   '[*]*') shift 2;;
>   *) shift
> esac
> IFS=" "
> set -- .[.]?* ${1+"$@"}
> case $1 in '.[.]?*') shift; esac
> set -- .[[]'!.]?*' .[!.]?* ${1+"$@"}
> case $1$2 in
>   '.[[]!.]?*.[!.]?*') shift 2;;
>   *) shift
> esac
>
> (won't give the same order as *(ND) either).

How about

set x *; shift
test $# -eq 1 && test "x$1" = x\* && ! test -e \* && shift
n=$#
set x .[!.]* ${1+"$@"}; shift
test $# -eq `expr $n + 1` && test "x$1" = 'x.[!.]?*' && ! test -e
'.[!.]?*' && shift
n=$#
set x ..?* ${1+"$@"}; shift
test $# -eq `expr $n + 1` && test ="x$1" = 'x..?*' && ! test -e '..?*' && shift

This tries to avoid using test -e (or whatever version of testing for
a files existence you’d like to use), but also avoids using patterns
just to test for failures to avoid unnecessary directory traversals.

It also avoids messing with IFS, but perhaps that’s necessary?

The ${1+"$@"} is to avoid an old Zsh bug, right?

It also avoids set --, as that’s apparently not portable either.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Equivalent of set -- *(DN) in sh
       [not found]         ` <CADdV=MsvuSAQMJVsr17Y7g2Nfjy95CQ007opQqv-7=RHjgjaKw__35342.9068615243$1421913204$gmane$org@mail.gmail.com>
@ 2015-01-22 15:21           ` Stephane Chazelas
  0 siblings, 0 replies; 15+ messages in thread
From: Stephane Chazelas @ 2015-01-22 15:21 UTC (permalink / raw)
  To: Nikolai Weibull; +Cc: Eric Cook, zsh-users

2015-01-22 08:44:40 +0100, Nikolai Weibull:
[...]
> set x *; shift
> test $# -eq 1 && test "x$1" = x\* && ! test -e \* && shift
> n=$#
> set x .[!.]* ${1+"$@"}; shift
> test $# -eq `expr $n + 1` && test "x$1" = 'x.[!.]?*' && ! test -e
> '.[!.]?*' && shift
> n=$#
> set x ..?* ${1+"$@"}; shift
> test $# -eq `expr $n + 1` && test ="x$1" = 'x..?*' && ! test -e '..?*' && shift
> 
> This tries to avoid using test -e (or whatever version of testing for
> a files existence you’d like to use)

Well, it doesn't try very hard does it ;-) ? Remember you need
test -e || test -L (or test -h on some old systems).

> but also avoids using patterns
> just to test for failures to avoid unnecessary directory traversals.

The directory content will be in cache after the first `set x
*`. Forking and exeuting some exprs is probably going to be
worse in most cases.

> It also avoids messing with IFS, but perhaps that’s necessary?

Well, yes "$@" in the Bourne shell relies on it containing space
and you're leaving a number of variables and command
substitutions unquoted.

Note that "case" has far fewer problems than "test".

> 
> The ${1+"$@"} is to avoid an old Zsh bug, right?

No, that's the other way round. ${1+"$@"} is to work around
problems with the Bourne shell (at least those where that has
not been fixed (where "$@" expands to one empty argument when $#
is 0)). zsh is the one that had problems with
${1+"$@"} (not "$@"), not really a bug, but down to how
parameter expansion nested.

Which is why you see things like:

test -z "$ZSH_VERSION" || alias -g '${1+"$@"}="$@"'

> It also avoids set --, as that’s apparently not portable either.


According to http://www.in-ulm.de/~mascheck/bourne/, -- was
added to the Bourne shell at the same time as [!...], so that
would suggest that if you want to account for those very old
systems, you can't use [!...] either. Note that old Bourne
shells didn't support characters with the 8th bit set either.

-- 
Stephane


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2015-01-22 15:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-18 18:28 Equivalent of set -- *(DN) in sh Nikolai Weibull
2015-01-18 19:07 ` Roman Neuhauser
2015-01-18 19:43   ` Nikolai Weibull
2015-01-18 20:32     ` Roman Neuhauser
2015-01-18 19:31 ` ZyX
2015-01-18 19:46   ` Nikolai Weibull
2015-01-18 20:46 ` Eric Cook
2015-01-19 15:51   ` ZyX
2015-01-19 15:55     ` ZyX
2015-01-19 16:02       ` ZyX
2015-01-19 16:16         ` ZyX
2015-01-19 21:44     ` Eric Cook
     [not found]     ` <54BD7ABB.5070501__36205.2317861982$1421704010$gmane$org@gmx.com>
2015-01-19 23:05       ` Stephane Chazelas
2015-01-22  7:44         ` Nikolai Weibull
     [not found]         ` <CADdV=MsvuSAQMJVsr17Y7g2Nfjy95CQ007opQqv-7=RHjgjaKw__35342.9068615243$1421913204$gmane$org@mail.gmail.com>
2015-01-22 15:21           ` Stephane Chazelas

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).