From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10763 invoked by alias); 20 Aug 2015 04:33:12 -0000 Mailing-List: contact zsh-users-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Users List List-Post: List-Help: X-Seq: 20437 Received: (qmail 7688 invoked from network); 20 Aug 2015 04:33:10 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.0 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:message-id:date:in-reply-to:comments :references:to:subject:cc:mime-version:content-type; bh=pbCv1IECdxHVpCzO7U3IM9bAR3YOO5hOQ1/rKpp6nbw=; b=KAI5Iz2p7NHpp0kI/MEiFs3SlJ/n9N6FXUq1x9VbEUYcXAEQlZkO2FkqxnXIjWbA0d 8mTznDyzTt+oCZzH8yBGzTR3Nsl2TMqC/xCwWDblemppLitk2smDJj3qa3E5PuKlovac 2zy6eAAK4aIDinyK0CQDwAcnoB5AzRZngowdMP07q6qjw5RDFRMSjK/pgUs/wrIRx+S0 ZcngfvsB4hP0WUW3g+PRdrkO3a1HqmNwGb0KjX0PHMzpMhfNCo/biyKRtzD29a3w34pk UF4ypoUZh/THFYCNCU32elbSFb+yJw2YWkctSc0uvxvD2qNo/Ly9ONXDVQwmDMsrx6Ld QiWg== X-Gm-Message-State: ALoCoQn/MKV2OC3/wyi2R9WFeCXZgH3rZXArBi0Uif5YgNKS/lckBoy39KcZ+dPQ1vCyL3EA1lQM X-Received: by 10.60.76.4 with SMTP id g4mr945016oew.81.1440045185790; Wed, 19 Aug 2015 21:33:05 -0700 (PDT) From: Bart Schaefer Message-Id: <150819213302.ZM28036@torch.brasslantern.com> Date: Wed, 19 Aug 2015 21:33:02 -0700 In-Reply-To: <6ac3d5e6.2de49d01.55d4fc3c.9415a@prokonto.pl> Comments: In reply to rooom "list last modified files" (Aug 19, 11:59pm) References: <6ac3d5e6.2de49d01.55d4fc3c.9415a@prokonto.pl> X-Mailer: OpenZMail Classic (0.9.2 24April2005) To: zsh-users@zsh.org Subject: Re: list last modified files Cc: rooom MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii 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 }