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