* Filtering argument lists (e.g. for grep)
@ 2015-12-07 10:56 Dominik Vogt
2015-12-07 11:18 ` Dominik Vogt
2015-12-07 11:23 ` Peter Stephenson
0 siblings, 2 replies; 8+ messages in thread
From: Dominik Vogt @ 2015-12-07 10:56 UTC (permalink / raw)
To: Zsh Users
For some commands, there are some file patterns that I never want
to pass to the command (unless explicitly stated otherwise). For
example, grep'ing should normally ignore backup and ChangeLog files
*ChangeLog*
*~
\#*
Maybe grep is a bad example because this can be done with the
--exclude= option. But could zsh help filtering the names
generated by globbing in a more general way so that I could write
$ <foo> *
and have zsh automagically filter the results of the * (not
everywhere; only for commands that have this feature enabled) so
that the non-matching names are not passed to the command in the
first place?
The only way I can think of is to write some function for each
command to be preprocessed, parse the arguments to figure out
which ones are file names and then use some utility function to
filter them.
Ciao
Dominik ^_^ ^_^
--
Dominik Vogt
IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 10:56 Filtering argument lists (e.g. for grep) Dominik Vogt
@ 2015-12-07 11:18 ` Dominik Vogt
2015-12-07 11:23 ` Peter Stephenson
1 sibling, 0 replies; 8+ messages in thread
From: Dominik Vogt @ 2015-12-07 11:18 UTC (permalink / raw)
To: Zsh Users
On Mon, Dec 07, 2015 at 11:56:22AM +0100, Dominik Vogt wrote:
> But could zsh help filtering the names
> generated by globbing in a more general way so that I could write
>
> $ <foo> *
>
> and have zsh automagically filter the results of the * (not
> everywhere; only for commands that have this feature enabled) so
> that the non-matching names are not passed to the command in the
> first place?
Or in other words: A context sensitive interpretation (or post
processing) of globbing patterns. Is that possible?
Ciao
Dominik ^_^ ^_^
--
Dominik Vogt
IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 10:56 Filtering argument lists (e.g. for grep) Dominik Vogt
2015-12-07 11:18 ` Dominik Vogt
@ 2015-12-07 11:23 ` Peter Stephenson
2015-12-07 11:39 ` Dominik Vogt
1 sibling, 1 reply; 8+ messages in thread
From: Peter Stephenson @ 2015-12-07 11:23 UTC (permalink / raw)
To: Zsh Users
On Mon, 7 Dec 2015 11:56:22 +0100
Dominik Vogt <vogt@linux.vnet.ibm.com> wrote:
> For some commands, there are some file patterns that I never want
> to pass to the command (unless explicitly stated otherwise). For
> example, grep'ing should normally ignore backup and ChangeLog files
>
> *ChangeLog*
> *~
> \#*
>
> Maybe grep is a bad example because this can be done with the
> --exclude= option. But could zsh help filtering the names
> generated by globbing in a more general way so that I could write
>
> $ <foo> *
>
> and have zsh automagically filter the results of the * (not
> everywhere; only for commands that have this feature enabled) so
> that the non-matching names are not passed to the command in the
> first place?
You could use a global alias, e.g.
alias -g '@*'='*~(*\~|\#*|ChangeLog)'
Ig you want that first * to be something more flexible you can use a
glob qualifier.
gi () {
[[ $REPLY != (*\~|\#*|ChangeLog) ]]
}
and use
<foo> *(+gi)
pws
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 11:23 ` Peter Stephenson
@ 2015-12-07 11:39 ` Dominik Vogt
2015-12-07 11:56 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:03 ` Nikolay Aleksandrovich Pavlov (ZyX)
0 siblings, 2 replies; 8+ messages in thread
From: Dominik Vogt @ 2015-12-07 11:39 UTC (permalink / raw)
To: Zsh Users
On Mon, Dec 07, 2015 at 11:23:54AM +0000, Peter Stephenson wrote:
> On Mon, 7 Dec 2015 11:56:22 +0100
> Dominik Vogt <vogt@linux.vnet.ibm.com> wrote:
> > Maybe grep is a bad example because this can be done with the
> > --exclude= option. But could zsh help filtering the names
> > generated by globbing in a more general way so that I could write
> >
> > $ <foo> *
> >
> > and have zsh automagically filter the results of the * (not
> > everywhere; only for commands that have this feature enabled) so
> > that the non-matching names are not passed to the command in the
> > first place?
> You could use a global alias, e.g.
>
> alias -g '@*'='*~(*\~|\#*|ChangeLog)'
Yes, but then I'd need an alias for every potential pattern, e.g.
@*.s*, @**/*, @*.c.* etc.
> Ig you want that first * to be something more flexible you can use a
> glob qualifier.
>
> gi () {
> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
> }
>
> and use
>
> <foo> *(+gi)
That sounds good, but is there a way to make that qualifier a
default for certain commands? As an alternative, is it possible
to access the command name from inside the qualifier function?
function gi () {
if <command should be filtered>; then
[[ $REPLY != (*\~|\#*|ChangeLog) ]]
fi
}
Ciao
Dominik ^_^ ^_^
--
Dominik Vogt
IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 11:39 ` Dominik Vogt
@ 2015-12-07 11:56 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:03 ` Nikolay Aleksandrovich Pavlov (ZyX)
1 sibling, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2015-12-07 11:56 UTC (permalink / raw)
To: vogt, Zsh Users
07.12.2015, 14:51, "Dominik Vogt" <vogt@linux.vnet.ibm.com>:
> On Mon, Dec 07, 2015 at 11:23:54AM +0000, Peter Stephenson wrote:
>> On Mon, 7 Dec 2015 11:56:22 +0100
>> Dominik Vogt <vogt@linux.vnet.ibm.com> wrote:
>> > Maybe grep is a bad example because this can be done with the
>> > --exclude= option. But could zsh help filtering the names
>> > generated by globbing in a more general way so that I could write
>> >
>> > $ <foo> *
>> >
>> > and have zsh automagically filter the results of the * (not
>> > everywhere; only for commands that have this feature enabled) so
>> > that the non-matching names are not passed to the command in the
>> > first place?
>
>> You could use a global alias, e.g.
>>
>> alias -g '@*'='*~(*\~|\#*|ChangeLog)'
>
> Yes, but then I'd need an alias for every potential pattern, e.g.
> @*.s*, @**/*, @*.c.* etc.
>
>> Ig you want that first * to be something more flexible you can use a
>> glob qualifier.
>>
>> gi () {
>> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
>> }
>>
>> and use
>>
>> <foo> *(+gi)
>
> That sounds good, but is there a way to make that qualifier a
> default for certain commands? As an alternative, is it possible
> to access the command name from inside the qualifier function?
>
> function gi () {
> if <command should be filtered>; then
> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
> fi
> }
I have pseudo-alias commands like zmw and zpy which do automagic escaping of their arguments (e.g. `zpy import zsh; print(zsh.getvalue("PATH"))` transforms into `zpython "import zsh; print(zsh.getvalue(\"PATH\"))"`) by hooking accept-line zle widget:
_-accept-line () {
emulate -L zsh
local -r autopushd=${options[autopushd]}
options[autopushd]=off
cd $PWD || cd
options[autopushd]=$autopushd
if [[ ${BUFFER[1,3]} = ":h " ]]
then
_HISTLINE=$BUFFER
BUFFER=":h ${(q)BUFFER[4,-1]}"
elif [[ ${BUFFER[1,4]} = "zmw " ]]
then
_HISTLINE=$BUFFER
BUFFER="zmw "${(j. .)${(q)${(z)BUFFER[5,-1]}}}
elif [[ ${BUFFER[1,4]} = "zpy " ]]
then
_HISTLINE=$BUFFER
BUFFER="zpython ${(qqq)BUFFER[5,-1]}"
fi
zle .accept-line
}
zle -N accept-line _-accept-line
. You may use the same technique to do anything you like with the line you typed, though this “anything” will sometimes be rather tricky to implement. `(z)` parameter expansion flag will be very useful on this path.
>
> Ciao
>
> Dominik ^_^ ^_^
>
> --
>
> Dominik Vogt
> IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 11:39 ` Dominik Vogt
2015-12-07 11:56 ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2015-12-07 12:03 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:06 ` Nikolay Aleksandrovich Pavlov (ZyX)
1 sibling, 1 reply; 8+ messages in thread
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2015-12-07 12:03 UTC (permalink / raw)
To: vogt, Zsh Users
07.12.2015, 14:51, "Dominik Vogt" <vogt@linux.vnet.ibm.com>:
> On Mon, Dec 07, 2015 at 11:23:54AM +0000, Peter Stephenson wrote:
>> On Mon, 7 Dec 2015 11:56:22 +0100
>> Dominik Vogt <vogt@linux.vnet.ibm.com> wrote:
>> > Maybe grep is a bad example because this can be done with the
>> > --exclude= option. But could zsh help filtering the names
>> > generated by globbing in a more general way so that I could write
>> >
>> > $ <foo> *
>> >
>> > and have zsh automagically filter the results of the * (not
>> > everywhere; only for commands that have this feature enabled) so
>> > that the non-matching names are not passed to the command in the
>> > first place?
>
>> You could use a global alias, e.g.
>>
>> alias -g '@*'='*~(*\~|\#*|ChangeLog)'
>
> Yes, but then I'd need an alias for every potential pattern, e.g.
> @*.s*, @**/*, @*.c.* etc.
>
>> Ig you want that first * to be something more flexible you can use a
>> glob qualifier.
>>
>> gi () {
>> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
>> }
>>
>> and use
>>
>> <foo> *(+gi)
>
> That sounds good, but is there a way to make that qualifier a
> default for certain commands? As an alternative, is it possible
> to access the command name from inside the qualifier function?
>
> function gi () {
> if <command should be filtered>; then
> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
> fi
> }
And there is another possibility: considering you want to do this thing with command `foo` you need to do the following:
1. Create an alias `foo='noglob foo'`.
2. Create a function `foo` like this:
function foo()
{
local -a args=( "${@[@]}" )
local -a new_args
for (( I=2; I<= $#args; I++ )) ; do
if [[ $args[I] != ${${args[I]}//[*?]} ]] ; then # If argument contains glob pattern
args[I]+="(+gi)"
new_args=( $~args[I] )
args[I,I]=( $new_args )
(( I += #new_args - 1 ))
fi
done
command foo "${args[@]}"
}
. I.e. in place of leaving zsh to expand globs, expand it in your function “manually”, with necessary additions.
>
> Ciao
>
> Dominik ^_^ ^_^
>
> --
>
> Dominik Vogt
> IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 12:03 ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2015-12-07 12:06 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:58 ` Nikolay Aleksandrovich Pavlov (ZyX)
0 siblings, 1 reply; 8+ messages in thread
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2015-12-07 12:06 UTC (permalink / raw)
To: vogt, Zsh Users
07.12.2015, 15:03, "Nikolay Aleksandrovich Pavlov (ZyX)" <kp-pav@yandex.ru>:
> 07.12.2015, 14:51, "Dominik Vogt" <vogt@linux.vnet.ibm.com>:
>> On Mon, Dec 07, 2015 at 11:23:54AM +0000, Peter Stephenson wrote:
>>> On Mon, 7 Dec 2015 11:56:22 +0100
>>> Dominik Vogt <vogt@linux.vnet.ibm.com> wrote:
>>> > Maybe grep is a bad example because this can be done with the
>>> > --exclude= option. But could zsh help filtering the names
>>> > generated by globbing in a more general way so that I could write
>>> >
>>> > $ <foo> *
>>> >
>>> > and have zsh automagically filter the results of the * (not
>>> > everywhere; only for commands that have this feature enabled) so
>>> > that the non-matching names are not passed to the command in the
>>> > first place?
>>
>>> You could use a global alias, e.g.
>>>
>>> alias -g '@*'='*~(*\~|\#*|ChangeLog)'
>>
>> Yes, but then I'd need an alias for every potential pattern, e.g.
>> @*.s*, @**/*, @*.c.* etc.
>>
>>> Ig you want that first * to be something more flexible you can use a
>>> glob qualifier.
>>>
>>> gi () {
>>> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
>>> }
>>>
>>> and use
>>>
>>> <foo> *(+gi)
>>
>> That sounds good, but is there a way to make that qualifier a
>> default for certain commands? As an alternative, is it possible
>> to access the command name from inside the qualifier function?
>>
>> function gi () {
>> if <command should be filtered>; then
>> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
>> fi
>> }
>
> And there is another possibility: considering you want to do this thing with command `foo` you need to do the following:
>
> 1. Create an alias `foo='noglob foo'`.
> 2. Create a function `foo` like this:
>
> function foo()
> {
> local -a args=( "${@[@]}" )
> local -a new_args
> for (( I=2; I<= $#args; I++ )) ; do
> if [[ $args[I] != ${${args[I]}//[*?]} ]] ; then # If argument contains glob pattern
> args[I]+="(+gi)"
> new_args=( $~args[I] )
> args[I,I]=( $new_args )
> (( I += #new_args - 1 ))
> fi
> done
> command foo "${args[@]}"
> }
>
> . I.e. in place of leaving zsh to expand globs, expand it in your function “manually”, with necessary additions.
Though this variant is for one command. For multiple you need some adjustments:
1. `alias foo='noglob filterglob foo'`
2. Function is `filterglob`, starts with `local -r cmd="$1"; shift`, ends with `command "$cmd" "${args[@]}"`.
And I should not have used `I=2` (it initially meant to skip command) in any case, replace `I=2` with `I=1`.
>
>> Ciao
>>
>> Dominik ^_^ ^_^
>>
>> --
>>
>> Dominik Vogt
>> IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Filtering argument lists (e.g. for grep)
2015-12-07 12:06 ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2015-12-07 12:58 ` Nikolay Aleksandrovich Pavlov (ZyX)
0 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2015-12-07 12:58 UTC (permalink / raw)
To: vogt, Zsh Users
07.12.2015, 15:18, "Nikolay Aleksandrovich Pavlov (ZyX)" <kp-pav@yandex.ru>:
> 07.12.2015, 15:03, "Nikolay Aleksandrovich Pavlov (ZyX)" <kp-pav@yandex.ru>:
>> 07.12.2015, 14:51, "Dominik Vogt" <vogt@linux.vnet.ibm.com>:
>>> On Mon, Dec 07, 2015 at 11:23:54AM +0000, Peter Stephenson wrote:
>>>> On Mon, 7 Dec 2015 11:56:22 +0100
>>>> Dominik Vogt <vogt@linux.vnet.ibm.com> wrote:
>>>> > Maybe grep is a bad example because this can be done with the
>>>> > --exclude= option. But could zsh help filtering the names
>>>> > generated by globbing in a more general way so that I could write
>>>> >
>>>> > $ <foo> *
>>>> >
>>>> > and have zsh automagically filter the results of the * (not
>>>> > everywhere; only for commands that have this feature enabled) so
>>>> > that the non-matching names are not passed to the command in the
>>>> > first place?
>>>
>>>> You could use a global alias, e.g.
>>>>
>>>> alias -g '@*'='*~(*\~|\#*|ChangeLog)'
>>>
>>> Yes, but then I'd need an alias for every potential pattern, e.g.
>>> @*.s*, @**/*, @*.c.* etc.
>>>
>>>> Ig you want that first * to be something more flexible you can use a
>>>> glob qualifier.
>>>>
>>>> gi () {
>>>> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
>>>> }
>>>>
>>>> and use
>>>>
>>>> <foo> *(+gi)
>>>
>>> That sounds good, but is there a way to make that qualifier a
>>> default for certain commands? As an alternative, is it possible
>>> to access the command name from inside the qualifier function?
>>>
>>> function gi () {
>>> if <command should be filtered>; then
>>> [[ $REPLY != (*\~|\#*|ChangeLog) ]]
>>> fi
>>> }
>>
>> And there is another possibility: considering you want to do this thing with command `foo` you need to do the following:
>>
>> 1. Create an alias `foo='noglob foo'`.
>> 2. Create a function `foo` like this:
>>
>> function foo()
>> {
>> local -a args=( "${@[@]}" )
>> local -a new_args
>> for (( I=2; I<= $#args; I++ )) ; do
>> if [[ $args[I] != ${${args[I]}//[*?]} ]] ; then # If argument contains glob pattern
>> args[I]+="(+gi)"
>> new_args=( $~args[I] )
>> args[I,I]=( $new_args )
>> (( I += #new_args - 1 ))
>> fi
>> done
>> command foo "${args[@]}"
>> }
>>
>> . I.e. in place of leaving zsh to expand globs, expand it in your function “manually”, with necessary additions.
>
> Though this variant is for one command. For multiple you need some adjustments:
>
> 1. `alias foo='noglob filterglob foo'`
> 2. Function is `filterglob`, starts with `local -r cmd="$1"; shift`, ends with `command "$cmd" "${args[@]}"`.
>
> And I should not have used `I=2` (it initially meant to skip command) in any case, replace `I=2` with `I=1`.
I have checked and the following filterglob function works:
filterglob () {
local -r cmd="$1"
shift
local -a args=("${@[@]}")
local -a new_args
for ((I=1; I<=$#args; I++ )) do
if [[ $args[I] != ${${args[I]}/[*?]} ]]
then
args[I]+="~*.png"
new_args=($~args[I])
args[I,I]=("${new_args[@]}")
(( I += #new_args - 1 ))
fi
done
"$cmd" "${args[@]}"
}
. But there is one downside: you need additional code to handle CSH_NULL_GLOB, NULL_GLOB and NOMATCH options. There are the following combinations:
1. nonomatch, nocshnullglob, nonullglob: leave pattern as-is. Requires 1. adding (N) at the end of the pattern 2. reverting args[I] change. (Note: *.c literally is also possible file name, so you can’t just “check if #new_args == 1 and new_args[1] == args[I] and if yes revert”, (N) is needed.)
2. cshnullglob, nonullglob: if there are no matches, leave no arguments, but if all patterns on the command-line have no matches, error out. Requires 1. adding (N) (or it will error out when processing new_args) 2. saving 1 if there were expanded globs.
3. nullglob: should work as-is, including when variant with (N) is used.
4. nomatch: should also work as-is, but when (N) is used requires additionally explicitly errorring out.
The final function works something like this:
filterglob () {
local -r cmd="$1"
shift
local -a args
args=( "${@[@]}" )
local -a new_args
local -i expandedglobs=0
local first_unexpanded_glob=
for ((I=1; I<=$#args; I++ )) do
if [[ $args[I] != ${${args[I]}/[*?]} ]]
then
local initial_arg=${args[I]}
args[I]+="~*.png(N)"
new_args=( $~args[I] )
if (( $#new_args )) ; then
expandedglobs=1
else
if [[ $options[cshnullglob] == off
&& $options[nullglob] == off ]] ; then
if [[ $options[nomatch] == on ]] ; then
: ${~${args[I]%\(N\)}} # Will error out.
else
new_args=( "$initial_arg" )
fi
fi
if [[ -z $first_unexpanded_glob ]] ; then
first_unexpanded_glob=${args[I]%\(N\)}
readonly first_unexpanded_glob
fi
fi
args[I,I]=( "${new_args[@]}" )
(( I += $#new_args - 1 ))
fi
done
if [[ $options[cshnullglob] == on && $options[nullglob] == off ]] ; then
if (( !expandedglob )) ; then
: $~first_unexpanded_glob # Will error out.
fi
fi
"$cmd" "${args[@]}"
}
. Note that this function has no `emulate -L zsh` at the top, so may be broken by some options. Also AFAIK you cannot use this specific function without `setopt extendedglob` and `zmodload zsh/parameter` (for `$options`).
// Do not forget to replace `~*.png` with whatever you need, I used this for testing purposes.
>>> Ciao
>>>
>>> Dominik ^_^ ^_^
>>>
>>> --
>>>
>>> Dominik Vogt
>>> IBM Germany
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-12-07 13:09 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-07 10:56 Filtering argument lists (e.g. for grep) Dominik Vogt
2015-12-07 11:18 ` Dominik Vogt
2015-12-07 11:23 ` Peter Stephenson
2015-12-07 11:39 ` Dominik Vogt
2015-12-07 11:56 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:03 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:06 ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-07 12:58 ` Nikolay Aleksandrovich Pavlov (ZyX)
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).