From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8362 invoked by alias); 3 Nov 2015 08:38:35 -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: 20890 Received: (qmail 14402 invoked from network); 3 Nov 2015 08:38:33 -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,FREEMAIL_FROM, T_DKIM_INVALID autolearn=ham autolearn_force=no version=3.4.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:cc:subject:message-id:mail-followup-to:references :mime-version:content-type:content-disposition:in-reply-to :user-agent; bh=AXUu72y/lW18TrVXf3FjbQi/l56heoj+s4FTcMTGhW8=; b=O/9XKJD/eVo0t6ohfEW+CnkDQiuoJqcR646pil09le6fBFai95CSLwGYwp6cHsawr1 gY53cI1hBXtI8b2g41H6yO8JJ5xqkxIMfWZlkT0U+xh1bBdk4GpN0G1EqFF7QHNFzI+Q dwQ+JLzvxFSZ63GpYKjv/YSTtNil7utJXBsJCtdL/n8ErVk81XehIkADY5X26fen+Uj2 p7a13fEHLKHXLhe80oU3btV0ZLLOQuaZofyFyn65KBwxGnO5PQOWnkft6jwmWpSMUYdT Ol2CynLc4+t3gWZsZju6SbUOpQb1MAJ33Vv6tKNFGqTarmBAP4FPHqe5ojH7QNL0xW9Q LMoQ== X-Received: by 10.28.18.3 with SMTP id 3mr18978487wms.67.1446536179004; Mon, 02 Nov 2015 23:36:19 -0800 (PST) Date: Tue, 3 Nov 2015 07:35:47 +0000 From: Stephane Chazelas To: Alexander Skwar Cc: zsh-users@zsh.org Subject: Re: for loop with parameter expansion in zsh vs. bash Message-ID: <20151103073547.GA6580@chaz.gmail.com> Mail-Followup-To: Alexander Skwar , zsh-users@zsh.org References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) 2015-11-03 07:52:51 +0100, Alexander Skwar: > Hello > > I've got a variable, where seperate values are limited with a delimiter. > Let's say PATH with : (but the question is general). > > With bash, I can easily create a for loop which loops over all the > elements, when I have bash replace the ":" with a " ", like so: ${PATH//:/ > }. > > a@ubuntu-notebook:~$ echo $PATH > /home/a/Applications/go/bin:/home/a/bin:/opt/bin:/opt/sbin:/usr/local/sbin:/usr/local/bin:/home/a/Applications/copy/x86_64:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/a/Applications/adt-bundle-linux-x86_64/sdk/platform-tools:/home/a/Applications/btsync:/home/a/.rvm/bin > > a@ubuntu-notebook:~$ for e in ${PATH//:/ }; do echo e: $e; done > e: /home/a/Applications/go/bin > e: /home/a/bin > e: /opt/bin > e: /opt/sbin > e: /usr/local/sbin > e: /usr/local/bin > e: /home/a/Applications/copy/x86_64 > e: /usr/sbin > e: /usr/bin > e: /sbin > e: /bin > e: /usr/games > e: /usr/local/games > e: /home/a/Applications/adt-bundle-linux-x86_64/sdk/platform-tools > e: /home/a/Applications/btsync > e: /home/a/.rvm/bin That approach is wrong. You're replacing : with space and invoking the split+glob operator (leaving an expansion unquoted in ksh/bash/sh, not zsh) with the default value of IFS which contains space, tab and newline. That means that approach only works if $PATH components don't contain blanks or wildcards. Here, you could use the split+glob operator, but you want to split on :, not blanks, and not invoke the glob part. So it would be (bash/ksh/sh, not zsh unless in sh/ksh emulation): IFS=: # split on : set -f # disabe glob for e in $PATH However with bash/ksh/sh (not zsh), it's still wrong, because it would discard a trailing empty component (like for a $PATH value of /bin:/usr/bin:) > > In zsh, the same for loop does not work (like it does in bash): No, because and that's the most FAQ for zsh, leaving a variable unquoted is not the split+glob operator (like it is in most other shells and the number one source of bugs and security vulnerabilities in them, (http://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells) In zsh, you invoke the split ($=var) or glob ($~var) operators explicitely, so: IFS=: for e in $~PATH Or use the "s" expansion flag: for e in "${(s(:))PATH}" For PATH however, you don't need to as zsh ties the $PATH variable to the $path array. So, it's just: for e in "$path[@]" -- Stephane