From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id f3e2fdee for ; Tue, 17 Dec 2019 09:40:25 +0000 (UTC) Received: (qmail 11128 invoked by alias); 17 Dec 2019 09:40:18 -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: List-Unsubscribe: X-Seq: 24565 Received: (qmail 23833 invoked by uid 1010); 17 Dec 2019 09:40:18 -0000 X-Qmail-Scanner-Diagnostics: from mail-io1-f47.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.102.1/25663. spamassassin: 3.4.2. Clear:RC:0(209.85.166.47):SA:0(-2.0/5.0):. Processed in 3.413978 secs); 17 Dec 2019 09:40:18 -0000 X-Envelope-From: mikachu@gmail.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _netblocks.google.com designates 209.85.166.47 as permitted sender) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=4Gf6xtvc92bqaVGjNL2/6XQoUCah68262w9O5nfH3bA=; b=ttiXbhYH/CPyx6Z0Arf5BV2zCKAr265HOm9H8JavxLNpLDvdKAtbWCuodKC2T8IQWA rzZ0xr/kJxoVUK2OunSfX/BM1MQUEhlVAXcTdSSipqGZkRpWxlA49otE9IXjCrDhWi4S Frc9xUAKCqcCecIKljr+1pQeEmOMwylbauAlFfDPgXKu4PNsSGw4ChtuaK69SsJYeSDO Jq3/9SuquQClzaE941Q3nFKtgyDaTYq9oiY6NmKJU8Q1EufJAJt7S43uCNGFtmFF/f3+ Q5yb0Fq9TeET7N6SLLyhk1K0DA0a0NMLmIw/8Elh09u0V1xR+v56Jx2NeKwGOzPuPwbK YC4w== X-Gm-Message-State: APjAAAVSH8HwvT1EVjHjgcsaiQPhgH4gVAqRLa+hdWAeCOiPjSCOV8Wd EyndDUnDOCLY7DtxruNyQY9XoS/o//AtL6uptCsWiw== X-Google-Smtp-Source: APXvYqwtfdg3BWXBL/iZrKe2OAqcAg/Qjz412RfDXNJrhEMGSn8G7skG9HSa/HRTGo3MPqlqNzz0flqXg9/c8k3mdOM= X-Received: by 2002:a6b:fe0f:: with SMTP id x15mr2784141ioh.219.1576575580966; Tue, 17 Dec 2019 01:39:40 -0800 (PST) MIME-Version: 1.0 In-Reply-To: <6f9d6ba5-3a24-e266-6b62-9473536b4a7f@goots.org> References: <15c62c86-5b55-e248-725f-4ecbfe73822d@goots.org> <6f9d6ba5-3a24-e266-6b62-9473536b4a7f@goots.org> From: Mikael Magnusson Date: Tue, 17 Dec 2019 10:39:40 +0100 Message-ID: Subject: Re: Glob and grep To: Nick Cross Cc: Zsh Users Content-Type: text/plain; charset="UTF-8" On 12/17/19, Nick Cross wrote: > On 16/12/2019 23:10, Mikael Magnusson wrote: >> On 12/16/19, Nick Cross wrote: >>> >>> Hi, >>> >>> I would like to condense the following into a single grep / glob >>> expression where I search recursively through a directory tree, ignoring >>> any sub-trees starting with 'test' or 'target'. >>> >>> grep **/*.groovy | egrep -v "(/test/|/target/)" >>> >>> Am I right in thinking I can add (.) to e.g. *.groovy to ensure I only >>> search for files as well ? >> >> I think what you want is >> grep (^(test|target)/)#*.groovy(.) >> > > Thats great thanks! Works perfectly. > > So to break it down - the ^ negates the or'd block. Can you explain how > the wrapped (../) and # then works please? Sure, you already know about the **/ operator, what you probably didn't know is that it's a shorthand for (*/)# which means */ repeated 0 or more times. We can replace the * by another pattern here, for example ((abc|xyz)/)# would match abc/abc and abc/xyz/xyz/abc/abc etc. A good way to think about (^foo) is like a * that will not expand to exactly foo. If you write *^hello you might think you'll match every file not ending in hello, but in fact you will match every file; the first * will simply match the entire string and then ^hello will match the empty string (or indeed "ello" or some other valid combination). The above method should be the most efficient way to do this, using **/*.groovy~*/(test|target)/* will first recurse through the entire tree, including test/ and target/, generate the whole list of matches, and then filter it by the pattern(s) given by ~. Depending on how large the test/target directories are, this can be a significant difference. It is probably easier to think about how ~ works though. -- Mikael Magnusson