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