* list last modified files @ 2015-08-19 21:59 rooom 2015-08-19 23:16 ` Vin Shelton 2015-08-20 4:33 ` Bart Schaefer 0 siblings, 2 replies; 13+ messages in thread From: rooom @ 2015-08-19 21:59 UTC (permalink / raw) To: zsh-users Hi, I'm trying to write a function which lists 10 most recent files from given sets (not only directories), something like trivial `alias lt=ls -lat | head -n 10`, but better. It should work like lt # list 10 recent files from . lt dir # list 10 recent files from dir/ lt dir1 file1 dir2/file* dir3 # list 10 recent files from a given sum of inputs Here is my solution so far, which I think is overcomplicated and iffy: lt() {ls -Adlt -- "${^@:-.}"(Ne:'[[ -d $REPLY ]] && reply=($REPLY/*(DNomon[1,10])) || true':) | head -n 10} Here how it should work: For each argument check if it is directory, and in that case return 10 most recent modified files from that directory, then add other arguments to the list (files) and ignore all non-file arguments (N). After all pass generated set to the 'ls' command which sorts it on modification time and finally pass to 'head -n 10'. Several question: 1. First of all I cannot understand why do I need a command "true" to list properly arguments which are not directories. I can put there other command as well like 'echo >/dev/null', but 'true' is simplest I could find (for example ':' doesn't work). From my basic understanding no command should be needed to properly handle 'lt file'. 2. I would like to get rid of external `head -n 10` command and use glob qualifiers instead, but as you can see there are already two nested qualifier lists, and I can't see a way to put one more after all of that just to take (om[1,10]). 3. When I run it with only non-existing files like 'lt nonexistingfile' then it prints single dot '.'. I would prefer to print error from 'ls' command like "ls: cannot access...". Note that I cannot remove (N) qualifier because zsh steps in with its own errors - I want zsh to pass argument to 'ls' as it is in case it cannot find files. Hope it's not too long, thanks in advance ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-19 21:59 list last modified files rooom @ 2015-08-19 23:16 ` Vin Shelton 2015-08-20 4:33 ` Bart Schaefer 1 sibling, 0 replies; 13+ messages in thread From: Vin Shelton @ 2015-08-19 23:16 UTC (permalink / raw) To: rooom; +Cc: zsh-users > I'm trying to write a function which lists 10 most recent files from given sets (not only directories), something like trivial `alias lt=ls -lat | head -n 10`, but better. Does ls -ld *(om[1,10]) do what you want? - Vin ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-19 21:59 list last modified files rooom 2015-08-19 23:16 ` Vin Shelton @ 2015-08-20 4:33 ` Bart Schaefer 2015-08-20 5:20 ` Mikael Magnusson 2015-08-20 13:08 ` rooom 1 sibling, 2 replies; 13+ messages in thread From: Bart Schaefer @ 2015-08-20 4:33 UTC (permalink / raw) To: zsh-users; +Cc: rooom On Aug 19, 11:59pm, rooom wrote: } } I'm trying to write a function which lists 10 most recent files } from given sets (not only directories), something like trivial } `alias lt=ls -lat | head -n 10`, but better. You can't glob if this is an arbibrary list of files. A glob qualifier can only be applied to files within a single directory (unless you can use a recursive glob like **/*) because you can't mix directory traversal with grouping, that is, (dir1/*|dir3/*) is an error. So you have to do one of -- (a) get all the file names+times and sort them yourself, then pass the first ten of them to "ls -lat" (b) get all the file names and let "ls -lat" sort them, then filter out all but the first ten Whichever of these you do, you have to filter all the files down to the first ten. You can do this inside zsh with e.g. an array slice or outside with "head" as you already did. However, you've thrown in this additional constraint: } 3. When I run it with only non-existing files like 'lt nonexistingfile' } then it prints single dot '.'. I would prefer to print error from 'ls' } command like "ls: cannot access...". That means you need the "nonomatch" option set, and you need to pass all the files (whether they exist or not) to "ls" so that it can generate the error messages. That pretty much eliminates option (a) [or makes it too messy to bother with], and since you're already using "ls" for the sorting, there's no benefit to avoiding "head". You're also probably better off testing the no-argument case separately rather than attempting to use ${@:-.}, because to get the behavior you describe in (3) you never really want to pass "./file" to "ls". Note that unless you want to "noglob" the whole thing or use nonomatch eveyrwhere, you won't be able to avoid having zsh print the error message when a pattern on the command line fails to match any files. } Here is my solution so far, which I think is overcomplicated and iffy: } } lt() {ls -Adlt -- "${^@:-.}"(Ne:'[[ -d $REPLY ]] && reply=($REPLY/*(DNomon[1,10])) || true':) | head -n 10} This is not far wrong, aside from the remark above about not passing "./" to "ls", but unless you think you're going to generate too many files for "ls -l" or that it will take too long, there's no reason to do the [1,10] in the glob qualifier. On the other hand, we've already established that you can't use a glob qualifier. } 1. First of all I cannot understand why do I need a command "true" to } list properly arguments which are not directories. I can put there } other command as well like 'echo >/dev/null', but 'true' is simplest I } could find (for example ':' doesn't work). The ":" doesn't work because you've used it as the delimiter for the (e:...:) qualifier. It's a little unintuitive, but due to order of parsing the quotes have been removed before the qualifier gets a chance to start looking for the matching colons. To explain why you need SOMETHING there: When [[ -d $REPLY ]] is not true, the entire && expression becomes false, and (e:false:) means to leave the file name out of the result. It might be more obvious to say you should have written: e:'[[ -d $REPLY ]] && reply=($REPLY/*) || reply=($REPLY)': Anyway here is my suggested function given all your constraints: lt() { setopt localoptions nonomatch local f local -a files for f; do [[ -d "$f" ]] && files+=( "$f"/* ) || files+=( "$f" ) done if [[ -n "${files[1]}" ]]; then ls -Adlt -- "${files[@]}" else ls -Adlt -- * fi | head -n 10 } ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 4:33 ` Bart Schaefer @ 2015-08-20 5:20 ` Mikael Magnusson 2015-08-20 13:08 ` rooom 1 sibling, 0 replies; 13+ messages in thread From: Mikael Magnusson @ 2015-08-20 5:20 UTC (permalink / raw) To: Bart Schaefer; +Cc: Zsh Users, rooom On Thu, Aug 20, 2015 at 6:33 AM, Bart Schaefer <schaefer@brasslantern.com> wrote: > On Aug 19, 11:59pm, rooom wrote: > } > } I'm trying to write a function which lists 10 most recent files > } from given sets (not only directories), something like trivial > } `alias lt=ls -lat | head -n 10`, but better. > > You can't glob if this is an arbibrary list of files. A glob qualifier > can only be applied to files within a single directory (unless you can > use a recursive glob like **/*) because you can't mix directory > traversal with grouping, that is, (dir1/*|dir3/*) is an error. So you > have to do one of -- You can do things like this though % mkdir ab ac bc dc; () { touch $^@/{foo,bar} } ?? % echo ((ab|b?)/)#foo(e:'(( RANDOM < 16000 ))':) ab/foo % echo ((ab|b?)/)#foo(e:'(( RANDOM < 16000 ))':) bc/foo You just can't have a / inside a (foo|bar) group, which you do potentially need sometimes. The pattern I used would also match ab/bd/ab/bn/foo recursively. -- Mikael Magnusson ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 4:33 ` Bart Schaefer 2015-08-20 5:20 ` Mikael Magnusson @ 2015-08-20 13:08 ` rooom 2015-08-20 13:29 ` Peter Stephenson 2015-08-23 20:35 ` ZLE: missing edit-buffer widget rooom 1 sibling, 2 replies; 13+ messages in thread From: rooom @ 2015-08-20 13:08 UTC (permalink / raw) To: zsh-users; +Cc: rooom Bart Schaefer wrote: > [...] Thank you for very detailed explanation!!! > The ":" doesn't work because you've used it as the delimiter for the > (e:...:) qualifier. It's a shame I didn't notice that. It's so obvious now. > for f; do And I've learnt on the occasion that 'for' loops over positional parameters by default, BTW, what is 'in'? $ type for in do done for is a reserved word in not found do is a reserved word done is a reserved word ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 13:08 ` rooom @ 2015-08-20 13:29 ` Peter Stephenson 2015-08-20 15:34 ` Bart Schaefer 2015-08-23 20:35 ` ZLE: missing edit-buffer widget rooom 1 sibling, 1 reply; 13+ messages in thread From: Peter Stephenson @ 2015-08-20 13:29 UTC (permalink / raw) To: zsh-users On Thu, 20 Aug 2015 15:08:02 +0200 rooom <rooom@prokonto.pl> wrote: > BTW, what is 'in'? It's simply a syntactic marker specific to "for" which looks for it in the list of arguments. In the original shell syntax it's not really doing much except make it a bit more readable since you're forced to use "for var in ...", but zsh makes a virtue of it by allowing you to do "for var1 var2... in ..." --- unless your variable is called "in", obviously, in which case you can't. pws ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 13:29 ` Peter Stephenson @ 2015-08-20 15:34 ` Bart Schaefer 2015-08-20 15:55 ` Peter Stephenson [not found] ` <20150820165552.2b5ec817__22391.7863135741$1440086232$gmane$org@pwslap01u.europe.root.pri> 0 siblings, 2 replies; 13+ messages in thread From: Bart Schaefer @ 2015-08-20 15:34 UTC (permalink / raw) To: zsh-users On Aug 20, 2:29pm, Peter Stephenson wrote: } } On Thu, 20 Aug 2015 15:08:02 +0200 } rooom <rooom@prokonto.pl> wrote: } > BTW, what is 'in'? } } It's simply a syntactic marker specific to "for" which looks for it in } the list of arguments. In the original shell syntax it's not } really doing much except make it a bit more readable since you're forced } to use "for var in ...", but zsh makes a virtue of it by allowing you } to do "for var1 var2... in ..." --- unless your variable is called "in", } obviously, in which case you can't. Well ... torch% for in in in; do print $in; done in torch% for in in in in in; do print $in; done in in in torch% unset in torch% for out in out in out; do print in:$in out:$out; done in: out:out in: out:in in: out:out torch% for in out in out in; do print $in $out; done out in torch% ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 15:34 ` Bart Schaefer @ 2015-08-20 15:55 ` Peter Stephenson 2015-08-20 17:13 ` Bart Schaefer [not found] ` <20150820165552.2b5ec817__22391.7863135741$1440086232$gmane$org@pwslap01u.europe.root.pri> 1 sibling, 1 reply; 13+ messages in thread From: Peter Stephenson @ 2015-08-20 15:55 UTC (permalink / raw) To: zsh-users On Thu, 20 Aug 2015 08:34:31 -0700 Bart Schaefer <schaefer@brasslantern.com> wrote: > On Aug 20, 2:29pm, Peter Stephenson wrote: > } > } On Thu, 20 Aug 2015 15:08:02 +0200 > } rooom <rooom@prokonto.pl> wrote: > } > BTW, what is 'in'? > } > } It's simply a syntactic marker specific to "for" which looks for it in > } the list of arguments. In the original shell syntax it's not > } really doing much except make it a bit more readable since you're forced > } to use "for var in ...", but zsh makes a virtue of it by allowing you > } to do "for var1 var2... in ..." --- unless your variable is called "in", > } obviously, in which case you can't. > > Well ... If you mean you'd rather blind me with code than state the rule... that worked. The rule is roughly: - Assume the first argument is a variable. This is needed for backwards compatibility. Note you can't do: vars=(one two three) for $vars in 1arg1 2arg1 3arg1 1arg2 2arg2 3arg2; ... - Otherwise, look for more variables until a word matches "in" (ignoring crazy variant zsh syntax) - If no "in", use positional parameters. - Otherwsie, any words after "in" are the arguments to loop over, taken in batches of the number of arguments before "in". The words are no longer subject to anything more than normal argument processing. The rule means this does work: set -- 1 2 3 4 5 6 for one two three; do print $one $two $three done 1 2 3 4 5 6 and you can replace "one" by "in" if you lke, but don't. pws ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 15:55 ` Peter Stephenson @ 2015-08-20 17:13 ` Bart Schaefer 0 siblings, 0 replies; 13+ messages in thread From: Bart Schaefer @ 2015-08-20 17:13 UTC (permalink / raw) To: Peter Stephenson; +Cc: Zsh Users On Thu, Aug 20, 2015 at 8:55 AM, Peter Stephenson <p.stephenson@samsung.com> wrote: > > If you mean you'd rather blind me with code than state the rule... > that worked. I wasn't expecting any response at all other than perhaps some amusement, but as long as we're stating rules: > - If no "in", use positional parameters. > - Otherwsie, any words after "in" are the arguments to loop over, > taken in batches of the number of arguments before "in". The > words are no longer subject to anything more than normal argument > processing. Except that "do" is a keyword, so it ends normal argument processing. (This is the point of Stephane's follow-up.) ^ permalink raw reply [flat|nested] 13+ messages in thread
[parent not found: <20150820165552.2b5ec817__22391.7863135741$1440086232$gmane$org@pwslap01u.europe.root.pri>]
* Re: list last modified files [not found] ` <20150820165552.2b5ec817__22391.7863135741$1440086232$gmane$org@pwslap01u.europe.root.pri> @ 2015-08-20 16:42 ` Stephane Chazelas 2015-08-20 17:09 ` Bart Schaefer 0 siblings, 1 reply; 13+ messages in thread From: Stephane Chazelas @ 2015-08-20 16:42 UTC (permalink / raw) To: Peter Stephenson; +Cc: zsh-users 2015-08-20 16:55:52 +0100, Peter Stephenson: [...] > set -- 1 2 3 4 5 6 > for one two three; do > print $one $two $three > done > > 1 2 3 > 4 5 6 > > and you can replace "one" by "in" if you lke, but don't. [...] Note that you can also do: for one two three do print $one $two $three done Note that "for i do" is Bourne and POSIX while "for i; do" is neither (though there's talk of making it standard in the next version of POSIX since most modern shells support it, and it's a common idiom). -- Stephane ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: list last modified files 2015-08-20 16:42 ` Stephane Chazelas @ 2015-08-20 17:09 ` Bart Schaefer 0 siblings, 0 replies; 13+ messages in thread From: Bart Schaefer @ 2015-08-20 17:09 UTC (permalink / raw) To: Peter Stephenson, Zsh Users On Thu, Aug 20, 2015 at 9:42 AM, Stephane Chazelas <stephane.chazelas@gmail.com> wrote: > > Note that you can also do: > > for one two three do > print $one $two $three > done Or even: for do do print $do; done But as Peter said, don't. ^ permalink raw reply [flat|nested] 13+ messages in thread
* ZLE: missing edit-buffer widget 2015-08-20 13:08 ` rooom 2015-08-20 13:29 ` Peter Stephenson @ 2015-08-23 20:35 ` rooom 2015-08-23 21:45 ` Bart Schaefer 1 sibling, 1 reply; 13+ messages in thread From: rooom @ 2015-08-23 20:35 UTC (permalink / raw) To: zsh-users Hi, Sometimes I want to edit multi line command with <up>/<down> arrows and in these cases push-line-or-edit widget is very helpful. However if activated for single line command it is equivalent to push-line (according to manual), so that I have to hit additional enter to get the line back. I'm looking for widget "edit-line" or "edit-buffer" which move entire command line into editor buffer regardless if it is single line or multi-line construct. For some reason the simple definition doesn't work: push-input-get-line () { zle .push-input zle .get-line } zle -N push-input-get-line Any suggestion? ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: ZLE: missing edit-buffer widget 2015-08-23 20:35 ` ZLE: missing edit-buffer widget rooom @ 2015-08-23 21:45 ` Bart Schaefer 0 siblings, 0 replies; 13+ messages in thread From: Bart Schaefer @ 2015-08-23 21:45 UTC (permalink / raw) To: zsh-users; +Cc: rooom On Aug 23, 10:35pm, rooom wrote: } } I'm looking for widget "edit-line" or "edit-buffer" which move entire } command line into editor buffer regardless if it is single line or } multi-line construct. Look at the edit-command-line function in the distribution (probably findable with print -R $^fpath/edit-command-line(N) ) You want to do what that does, except skip invoking the editor on a file. So something like: print -Rz - "$PREBUFFER$BUFFER" zle send-break This is exactly what push-line-or-edit does except that if there is only one line of input it skips the send-break. (push-line-or-edit was implemented before user-defined widgets were available.) You could also write a little wrapper that's just a no-op if there is only one line: edit-if-multi-line () { if [[ -n "$PREBUFFER" ]]; then zle .push-line-or-edit fi return 0 } } For some reason the simple definition doesn't work: } } push-input-get-line () { } zle .push-input } zle .get-line } } You've discovered the reason push-line-or-edit exists. In a multi- line construct, the stuff entered at previous prompts (the value of $PREBUFFER) has already passed through both the editor and the shell parser and is only awaiting the completion of the parse to be run as shell input. In order to get it back and undo the parser state, push-input has to abort the whole parser loop, so get-line never has a chance to be executed. ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2015-08-23 21:45 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-08-19 21:59 list last modified files rooom 2015-08-19 23:16 ` Vin Shelton 2015-08-20 4:33 ` Bart Schaefer 2015-08-20 5:20 ` Mikael Magnusson 2015-08-20 13:08 ` rooom 2015-08-20 13:29 ` Peter Stephenson 2015-08-20 15:34 ` Bart Schaefer 2015-08-20 15:55 ` Peter Stephenson 2015-08-20 17:13 ` Bart Schaefer [not found] ` <20150820165552.2b5ec817__22391.7863135741$1440086232$gmane$org@pwslap01u.europe.root.pri> 2015-08-20 16:42 ` Stephane Chazelas 2015-08-20 17:09 ` Bart Schaefer 2015-08-23 20:35 ` ZLE: missing edit-buffer widget rooom 2015-08-23 21:45 ` Bart Schaefer
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).