Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: setopt and alias questions



On Feb 7, 11:52pm, Sweth Chandramouli wrote:
} Subject: Re: setopt and alias questions
}
} 	here's the workaround i just came up with; it depends on the
} fact that the options that already start with "no" (e.g. notify) are,
} by default, on.

Believe it or not, the C code for "setopt" depends on exactly the same
fact.

It should be noted that this function only works properly in zsh 3.1.2
and later, because prior to that the first line of output from `setopt`
with kshoptionprint on, is "Current option settings".

I'm also having some other problems with it.  I had to change the "for"
loop expression to:

	for OPT_PAIR in "${(@f)$(builtin setopt)}"; do

in order to get the proper split-by-lines behavior.  I'm at a loss what
would let it work for you without the quotes and the @ flag.

} it probably needs a test at the beginning to see
} what the current value of kshoptionprint is, but since i won't ever
} be setting that option manually now that i have this function, i
} didn't bother to put it in.

The canonical way to do this is

	setopt localoptions kshoptionprint

The "localoptions" causes the values of all options to revert when the
function returns to their state at the time the function was entered.

Of course, both localoptions and kshoptionprint will be mis-reported in
the resulting output, but that's no big deal.

} allopt () {
}    builtin setopt kshoptionprint
}    for OPT_PAIR in ${(f)$(builtin setopt)} ; do
}       OPT_VALUE=$((${#${(M)OPT_PAIR% *}}%2))

Wow.  No offense, but if we ever decide to have an obfuscated zsh code
contest, that's got to be a leading candidate.  For the confused, this
gets the trailing " on" or " off" (note leading space!) from a string
like "norcs                 on", gets its length (3 for on, 4 for off)
and uses mod-2 arithmetic to turn that into 1 for on or 0 for off.

}       OPT_NAME=${OPT_PAIR% *}

This sets OPT_NAME to "norcs                " (note all the trailing
spaces).  Better might be ${OPT_PAIR%% *} to trim the spaces; doubling
the % makes it consume the longest match rather than the shortest.  (I
say "might be" because this function doesn't actually care whether the
spaces are there or not.)

}       if [[ ${OPT_NAME#no} != ${OPT_NAME} ]] ; then
}          OPT_VALUE=$(( (${OPT_VALUE}+1)%2 )) &&
}             OPT_NAME=${OPT_NAME#no};
}       fi;

Using our "norcs" example, this changes OPT_VALUE from 1 to 0 by using
modulo arithmetic again, and changes OPT_NAME from norcs to rcs (still
plus all the trailing space).

If the option hadn't started with "no", nothing would have changed.

}       if [[ ${OPT_VALUE} = 1 ]] ; then
}          OPT_VALUE='on'
}       else OPT_VALUE='off'
}       fi;
}       echo ${(r:28:)OPT_NAME} ${OPT_VALUE}
}    done
}    builtin unsetopt kshoptionprint
} }

That part is pretty obvious.

So here's what I hope is a somewhat more readable version of the whole
function:

    allopt() {
	builtin setopt localoptions kshoptionprint
	local OPT_PAIR OPT_VALUE OPT_NAME
	for OPT_PAIR in "${(@f)$(builtin setopt)}"
	do
	    OPT_NAME=${OPT_PAIR%% *}
	    OPT_VALUE=${OPT_PAIR##* }
	    if [[ ${OPT_NAME#no} != $OPT_NAME ]]
	    then
		OPT_NAME=${OPT_NAME#no}
		[[ $OPT_VALUE == off ]] && OPT_VALUE=on || OPT_VALUE=off
	    fi
	    echo ${(r:21:)OPT_NAME} ${OPT_VALUE}
	done
    }

I chose (r:21:) because that's how wide the actual "setopt" output is.

} > Zsh does not export aliases.  
} 	so aliases to be present in all interactive shells must be
} defined in .zshrc?

Yes.

} aside from global aliases, is there any reason
} to not put all of my aliases into equivalent functions?

Probably not.  (Functions aren't exported either, though.)

} > I don't know what you mean by "tracking."
} tracking means that when an alias is first invoked, its definition is
} modified as though all commands it calls were defined with their full
} paths.

Ah.  No, zsh definitely does not do this.

Zsh does modify function definitions the first time that they're loaded
to contain the expansions of any already-extant aliases, and then never
expands aliases when executing the function.  So once a function has
been loaded, you can change your aliases all you like without affecting
the function.  There's a lot about this in the FAQ.

} [...] it can be used, by aliasing commands like ls, to help prevent 
} problems caused by insecure paths--once a command that has been "wrapped"
} by its alias has been invoked, subsequent invocations will refer back
} to that original command, as opposed to, say, an evil trojan in the current
} directory that would otherwise have been run by a PATH containing ".".

Hrm.  Zsh actually goes out of its way to make "." in $PATH work even if
the command has previously been hashed to somewhere (later) in the path.
"Tracking" of aliases for speed purposes wouldn't be of much use in zsh
unless the hashcmds option is off.

Anyway, that sounds like a pretty insecure way to give the illusion of
greater security.  You're protected only if the alias is first invoked in
a "safe" location -- if the evil trojan is already present the first time
you use the alias, you're still in trouble.  (Unless it doesn't really
work exactly the way you described it.)

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com



Messages sorted by: Reverse Date, Date, Thread, Author