zsh-users
 help / color / mirror / code / Atom feed
* avoid eval?
@ 2018-03-11 20:48 Ray Andrews
  2018-03-11 22:53 ` Marc Chantreux
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2018-03-11 20:48 UTC (permalink / raw)
  To: Zsh Users

func ()

{

     sstring="$@"
     eval cp oldfile \""${(f)sstring}"\"

}

$ func now is the time

$ func filenames should not have spaces
'oldfile' -> 'filenames should not have spaces'

It's easy enough if there are no spaces in the target name, but I don't 
seem to be able to avoid the 'eval' construction if there are spaces.  
Is there a simpler way to simulate quotation marks:

$ cp oldfile "now is the time"

... within the function?  The way I have it is surely a bit abominable, 
somehow 'cp' needs to know that "now is the time" is one argument.  I 
should know this.



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

* Re: avoid eval?
  2018-03-11 20:48 avoid eval? Ray Andrews
@ 2018-03-11 22:53 ` Marc Chantreux
  2018-03-12  0:43   ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Marc Chantreux @ 2018-03-11 22:53 UTC (permalink / raw)
  To: zsh-users

hello,

> ... within the function?  The way I have it is surely a bit abominable,
> somehow 'cp' needs to know that "now is the time" is one argument.  I should
> know this.

"$@" expands as an array and "$*" expands as a string so

func () cp oldfile "$*"

should probably do what you expect.

regards
marc


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

* Re: avoid eval?
  2018-03-11 22:53 ` Marc Chantreux
@ 2018-03-12  0:43   ` Ray Andrews
  2018-03-13  2:13     ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2018-03-12  0:43 UTC (permalink / raw)
  To: zsh-users

On 11/03/18 03:53 PM, Marc Chantreux wrote:
> "$@" expands as an array and "$*" expands as a string so
> func () cp oldfile "$*"
>
> should probably do what you expect.
>
> regards
> marc
>
Thanks so it does.  I tried that and 50 other ideas.  I just now 
realized it was because I had $IFS=$'\n'

set in another function :-(  Cost me half the day.


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

* Re: avoid eval?
  2018-03-12  0:43   ` Ray Andrews
@ 2018-03-13  2:13     ` Ray Andrews
  2018-03-13  2:17       ` Eric Cook
  2018-03-13 16:36       ` (some tips about variables) " Marc Chantreux
  0 siblings, 2 replies; 9+ messages in thread
From: Ray Andrews @ 2018-03-13  2:13 UTC (permalink / raw)
  To: zsh-users

On 11/03/18 05:43 PM, Ray Andrews wrote:
> On 11/03/18 03:53 PM, Marc Chantreux wrote:
>> "$@" expands as an array and "$*" expands as a string so
>> func () cp oldfile "$*"
>>
>>
> Thanks so it does.  I tried that and 50 other ideas.  I just now 
> realized it was because I had $IFS=$'\n'
>
> set in another function :-(  Cost me half the day.
>
Is there any way to immunize my functions against $IFS trouble?  I have 
functions that seem to require " $IFS=$'\n' " and others that insist on 
" $IFS=' '  ".  It would be nice if I didn't have to reset it in each 
function.  I'll bet there will be syntax that always does the right 
thing regardless of $IFS.



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

* Re: avoid eval?
  2018-03-13  2:13     ` Ray Andrews
@ 2018-03-13  2:17       ` Eric Cook
  2018-03-13 16:36       ` (some tips about variables) " Marc Chantreux
  1 sibling, 0 replies; 9+ messages in thread
From: Eric Cook @ 2018-03-13  2:17 UTC (permalink / raw)
  To: zsh-users

On 03/12/2018 10:13 PM, Ray Andrews wrote:
> On 11/03/18 05:43 PM, Ray Andrews wrote:
>> On 11/03/18 03:53 PM, Marc Chantreux wrote:
>>> "$@" expands as an array and "$*" expands as a string so
>>> func () cp oldfile "$*"
>>>
>>>
>> Thanks so it does.  I tried that and 50 other ideas.  I just now realized it was because I had $IFS=$'\n'
>>
>> set in another function :-(  Cost me half the day.
>>
> Is there any way to immunize my functions against $IFS trouble?  I have functions that seem to require " $IFS=$'\n' " and others that insist on " $IFS=' '  ".  It would be nice if I didn't have to reset it in each function.  I'll bet there will be syntax
> that always does the right thing regardless of $IFS.
> 
> 

In the 10 or so years that i have used zsh, i've never needed to change IFS. but in the functions that you think that you need to change IFS,
you would just use local to scope the change to that function.


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

* (some tips about variables) Re: avoid eval?
  2018-03-13  2:13     ` Ray Andrews
  2018-03-13  2:17       ` Eric Cook
@ 2018-03-13 16:36       ` Marc Chantreux
  2018-03-13 17:50         ` Ray Andrews
  1 sibling, 1 reply; 9+ messages in thread
From: Marc Chantreux @ 2018-03-13 16:36 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

hello,

> Is there any way to immunize my functions against $IFS trouble?  I have
> functions that seem to require " $IFS=$'\n' " and others that insist on "
> $IFS=' '  ".

you should be carreful to reduce the scope of the change of such an
important variable. more generally, you should localize every variables
of the functions using local.

also, you can make your functions more reliable by reporting when

* you are using unset variables
* you are setting a global variable in the functions

to summarize:

* use zsh options that protects you from mistakes

    setopt warncreateglobal nounset

* keep the IFS change as tight as possible by setting it for only one
  read. exemples

    getent passwd |
        while {IFS=: read login _ uid gid gecos home shell } {
            [[ $shell == *zsh* ]] && print $login is cool
        }

    slurp     () { IFS=$'\n' read -d '' -A $1 }
    readlines () { local _; IFS=$'\n' read -d '' "$@" _ }

* at least, localize your variables

    slurp     () { local IFS=$'\n'  ; read -d '' -A $1 }
    readlines () { local _IFS=$'\n' ; read -d '' "$@" _ }


regards,
marc


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

* Re: (some tips about variables) Re: avoid eval?
  2018-03-13 16:36       ` (some tips about variables) " Marc Chantreux
@ 2018-03-13 17:50         ` Ray Andrews
  2018-03-13 20:39           ` Marc Chantreux
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2018-03-13 17:50 UTC (permalink / raw)
  To: zsh-users

On 13/03/18 09:36 AM, Marc Chantreux wrote:

> you should be carreful to reduce the scope of the change of such an
> important variable. more generally, you should localize every variables
> of the functions using local.
>
Right, as Eric also suggested.
>      setopt warncreateglobal nounset
That's an entirely new idea, I'll study it.
> * keep the IFS change as tight as possible by setting it for only one
>    read. exemples
>
>      getent passwd |
>          while {IFS=: read login _ uid gid gecos home shell } {
>              [[ $shell == *zsh* ]] && print $login is cool
>          }
>
Well, it it can be *that* local, just for one loop, then that makes 
things much simpler.

Still there are mysteries:

function test ()
{
local IFS=$'\n'
echo $path[2]
tty=( `stty size` )         # Grab the size of the terminal.
echo $tty
echo $tty[1]
local IFS=' '
echo $path[2]
tty=( `stty size` )         # Grab the size of the terminal.
echo $tty
echo $tty[1]
}

$ . ./test; test
/aWorking/Zsh/System
52 80
52 80
/aWorking/Zsh/System
52 80
52



... $path is space-separated, yet it is 'immune' to IFS issues. Array 
$tty, it is not immune to IFS.  I suspect that's because maybe $path is 
not an array, and it would appear that IFS only applies to arrays (?) 
but if so, how does one tell one from the other?  It seems counter 
intuitive that "$tty[1]" and "$tty" could mean the same thing in any 
situation.  Splitting issues seem the one thing that is always hard to 
get right, there seem to be dozens of variations on the theme.


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

* (some tips about variables) Re: avoid eval?
  2018-03-13 17:50         ` Ray Andrews
@ 2018-03-13 20:39           ` Marc Chantreux
  2018-03-13 21:50             ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Marc Chantreux @ 2018-03-13 20:39 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

hello,

> Well, it it can be *that* local, just for one loop, then that makes things
> much simpler.

yes it can. another way to keep things very local is to use anonymous
functions so you can write in the middle of your script

    () {
        local user
        for user { print "hello $user" }
    } bob joe ted

    print "finally: hello ${user:-world}"

which gives you

    hello bob
    hello joe
    hello ted
    finally: hello world

> Still there are mysteries:
> function test ()

wow .. don't overwrite an existing command, ever!
(note: it would be cool to rise a warning when you do that)


> local IFS=$'\n'
> echo $path[2]
> tty=( `stty size` )         # Grab the size of the terminal.
> echo $tty
> echo $tty[1]
> local IFS=' '
> echo $path[2]
> tty=( `stty size` )         # Grab the size of the terminal.
> echo $tty
> echo $tty[1]
> }

> 
> $ . ./test; test
> /aWorking/Zsh/System
> 52 80
> 52 80
> /aWorking/Zsh/System
> 52 80
> 52


> ... $path is space-separated, yet it is 'immune' to IFS issues. Array $tty,

you can check the type of a variable using the (t) modifier.

    print ${(t)path}
    array-special

> it is not immune to IFS. I suspect that's because maybe $path is not an
> array,

can you please show a little case where something isn't working ? i
don't understand the problem you're facing.

reading the values of a command with multiple values, a lovely thing
about zsh (unique, i think) is that you can use read at the end of a
pipe so for example:

    # mocking ssty
    stty () print 20 30
    local -A stty
    stty size | read stty\[{x,y}]
    print $stty[x] # prints 20

> how does one tell one from the other? It seems counter intuitive that
> "$tty[1]" and "$tty" could mean the same thing in any situation.

    # mocking ssty
    stty () print 20 30
    stty=( `stty size` )
    i=0; for el ($stty) print $[i++] : $el

    0 : 20
    1 : 30

the thing works the way you expect because IFS is the default one: "$'\t' ".

now if you set IFS you got

    # mocking ssty
    IFS=:
    stty () print 20 30
    stty=( `stty size` )
    i=0; for el ($stty) print $[i++] : $el 

because zsh found no ':' to split the result the whole line is stored as
$stty[1]. in this case as $stty contains only $stty[1]:

    0 : 20 30

> Splitting
> issues seem the one thing that is always hard to get right,
> there seem to be dozens of variations on the theme.

IFS is the field separator, $'\n' is the record separator so if you set
IFS to $'\n' you can't basically split nothing captured by read.

you can change the record separator with 'read -d'

I show you an example in the previous mail

    slurp () IFS=$'\n' read -d '' -A $1
    hosts=()
    grep '^[^#]' /etc/hosts | slurp hosts
    print $hosts[1]

outputs

    127.0.0.1	localhost

regards
marc



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

* Re: (some tips about variables) Re: avoid eval?
  2018-03-13 20:39           ` Marc Chantreux
@ 2018-03-13 21:50             ` Ray Andrews
  0 siblings, 0 replies; 9+ messages in thread
From: Ray Andrews @ 2018-03-13 21:50 UTC (permalink / raw)
  To: zsh-users

On 13/03/18 01:39 PM, Marc Chantreux wrote:
>
> yes it can. another way to keep things very local is to use anonymous
> functions so you can write in the middle of your script
>
>      () {
>          local user
>          for user { print "hello $user" }
>      } bob joe ted

More good advice, thanks Marc, I haven't used those yet.

> wow .. don't overwrite an existing command, ever! 

To be honest,  I never considered that there was an existing command, I 
see there is, but whatever it is, I never use it.  I'll pay attention to 
that now.


> you can check the type of a variable using the (t) modifier.
>      print ${(t)path}
>      array-special
>

Thanks, I forgot about that.

> IFS is the field separator, $'\n' is the record separator so if you set
> IFS to $'\n' you can't basically split nothing captured by read.

Ha!  Now I know the difference, I thought they were the same.  You open 
my eyes Marc.  More latter.


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

end of thread, other threads:[~2018-03-13 22:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-11 20:48 avoid eval? Ray Andrews
2018-03-11 22:53 ` Marc Chantreux
2018-03-12  0:43   ` Ray Andrews
2018-03-13  2:13     ` Ray Andrews
2018-03-13  2:17       ` Eric Cook
2018-03-13 16:36       ` (some tips about variables) " Marc Chantreux
2018-03-13 17:50         ` Ray Andrews
2018-03-13 20:39           ` Marc Chantreux
2018-03-13 21:50             ` Ray Andrews

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).