Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to do something like:

$ convert [a,b,c,d,e].png -resize 50% <current_match>_half.png

How can I do this? Is there some variable that stores the current match? I couldn't find anything in the docs but maybe I'm looking for the wrong keywords.

I thought maybe I could do it with xargs but I couldn't work that out either.

share|improve this question

2 Answers 2

up vote 2 down vote accepted

I would probably write it as a loop over the glob-generated names:

for f in [abcde].png; do
    convert "$f" -resize 50% "${f%.png}"_half.png
done

Note: Nothing in the above example is specific to zsh; it should work in any POSIX-compatible shell (dash, ksh, bash, zsh, etc.; including just about any modern version of sh).

Stephane Chazelas also notes that zsh has a different default behavior for when the glob fails to match any files: it gives an error message instead of using the pattern itself as the sole “result” of the expansion. This behavior for this situation is also adjustable in other shells (e.g. the failglob and nullglob options in bash, the special ~(N) glob prefix in ksh, the NOMATCH and NULL_GLOB options in zsh).

share|improve this answer
    
${var%pattern} is POSIX but not Bourne though. Also note that in other shells than zsh it might convert a file called [abcde].png if there's no file matching that glob, so one could say that this answer is zsh specific. Another way to make it zsh specific is to write it: for f ([a-e].png) convert $f -resize 50% ${f:r}_half.png –  Stéphane Chazelas Feb 27 '13 at 6:33

ImageMagick tools have a limited wildcard capability. If you pass multiple file names or the literal wildcard, it will create output files with sequential numbering, for example:

convert [a-e].png -resize 50% half.png

creates half-0.png, half-1.png, etc.

If you want to match the input file names, you'll have to call convert on one file at a time, in a loop, explicitly or via a tool. (Alternatively, you could rename the files afterwards, but there's no advantage in doing that.) Inside the loop, you can use zsh's filename manipulation or string manipulation constructs.

for i in [a-e].png; do
  convert $i -resize 50% %{i:t}_half.png
done

If you use this in a script, you may want to add the N glob qualifier so that the wildcard pattern expands to nothing if there is no matching file: for i in [a-e].png(N); do …

Zsh comes with a tool to rename files based on patterns: zmv. You can use it for other name-based transformations.

autoload -U zmv
zmv -p convert -o '-resize 50%' '([a-e]).png' '${1}_half.png'

Alternate ways to write those name patterns include:

zmv -p convert -o '-resize 50%' '([a-e])(.png)' '${1}_half$2'
zmv -p convert -o '-resize 50%' -w '[a-e].png' '${1}_half.png'
zmv -p convert -o '-resize 50%' '[a-e].png' '${f:t}_half.png'

You can make aliases to put in your .zshrc:

autoload -U zmv
alias zcp='zmv -C'
alias zln='zmv -L'
alias zconvert='zmv -p convert'

The following wrapper is a bit nicer than the alias above as it removes the requirement of passing all the options to convert inside quotes. If you pass any zmv options, they must come before all convert options.

zconvert () {
  typeset -a zmv_options=
  while [[ $1 = -[finqQsvwW] ]]; do
    zmv_options+=($1)
  done
  zmv -p convert $zmv_options -o "$@[1,-3]" $@[-2] $@[-1]
}
share|improve this answer
    
Wow, this is a brilliant answer. –  Mike H-R Aug 28 at 13:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.