If I want to convert a pdf to a png image with imagemagick I do something like:

convert -trim -density 400 this_is_a_very_long_filename_of_my_pdf_file.pdf this_is_a_very_long_filename_of_my_pdf_file.png

The pdf file often has a very long file name for some reasons and I want that the png file has the same name except of the extension.

Usually I select this_is_a_very_long_filename_of_my_pdf_file.pdf twice via tab and zsh-menu and change then pdf to png manually for the second argument.

However is there a faster way to do this?

6 Answers 6


You can use brace expansions:

convert -trim -density 400 this_is_a_very_long_filename_of_my_pdf_file.{pdf,png}
  • 1
    Can also note filename autocompletion (it's present in zsh, isn't it?)
    – Ruslan
    Jul 6, 2014 at 18:39
  • @Ruslan The OP said he uses autocomplete. But still, nice time saving point.
    – cubecubed
    Jul 6, 2014 at 21:43

This call to mogrify will create a new png file instead of overwriting the pdf - hopefully ;)

mogrify -trim density 400 -format png th*.pdf

for th*.pdf use the aprropriate number of characters to select the right file or better tab completion until you have the full name.

This way you can make an alias to the whole command up to the png parameter.


If you always use the same command with small variations (such as the file name), you can write a function:

pdf2png() { convert -trim -density 400 "$1" "$1:r.png" }

(this function is specific to zsh), and for each file your_file.pdf you want to convert:

pdf2png your_file.pdf

Note 1: You can write the same kind of function for other shells, but this is a bit more complex.

Note 2: With zsh, the quotes are useful only if the SH_WORD_SPLIT option is set (which is not the default).


Consider using variables to store your filenames. They autocomplete too:

convert -trim -density 400 "$f.pdf" "$f.png"

I use quotes because sometimes spaces bite.

Significant benefits of this are:

  1. You can perform further operations with the value in $f, knowing it points to the right file
  2. It is the shortest of hops to stick this in a cat listOfFiles | while read f; do ... ; done loop structure.
  3. Often auto-generated filenames are very similar, and the auto-complete gets very annoying very quickly if you have to do abc<tab>d<tab>x<tab>2<tab> etc. This way, you only have to type it once, and you can even pick up the latest file or the largest file via a script like f=\ls -t | head -1``, instead of first running the search, looking for the filename and transcribing it like some sort of trained monkey.

You can also use History Expansion to refer to words on the current command line:

convert -trim -density 400 this_is_a_very_long_filename_of_my_pdf_file.pdf !#:$:r.png
  • Event designator !# refers to the command line typed so far
  • Word designator $ indicates the last word (before the expansion)
  • Modifier r removes the file extension. This also marks the end of the text, which is replaced when history expansion occurs.
  • .png is the new extension. This does not belong to the expansion itself.

When this line is run, !#:$:r is replaced by the name of your pdf file minus the extension, thus creating the command from the question:

convert -trim -density 400 this_is_a_very_long_filename_of_my_pdf_file.pdf this_is_a_very_long_filename_of_my_pdf_file.png

This line is then directly executed.

If you want to check the command after history expansion, before execution, use

setopt histverify

This will reload the expanded line into the editing buffer instead of executing it.

Note: Unlike any other expansion, history expansion is performed before the command is saved to the history. So echo !# will appear as echo echo and not as echo !# in your $HISTFILE.


Using brace expansion cannot be beaten for this special example. However, a little more flexible is the zle widget copy-prev-shell-word, which does what it's name suggests and is handy if you want a similar argument as the previous, which cannot systematically derived from it.

Bind the widget e.g. to CTRL+W:

bindkey '^W' copy-prev-shell-word

If you are as lazy as I am, use this bindkey sequence

bindkey '^W^W' copy-prev-shell-word
bindkey -s '^W' ' ^W^W'

to get the following behaviour:

  • CTRL+W inserts the previous shell word with a leading blank (hence, you save one keystroke!)
  • CTRL+W CTRL+W inserts the previous shell word directly

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .