1

I have following script (named vid2gif.sh) to convert a video file to gif:

#! /bin/bash
ffmpeg -i $1 /tmp/gif/out%04d.gif
gifsicle --delay=10 --loop /tmp/gif/*.gif > $2

I can convert a file using command:

vid2gif.sh myvid.mp4 myvid.gif

How can I make it to convert all mp4 files in a folder? That is, how can I make following command work:

vid2gif.sh *.mp4

The script should output files as *.gif. Thanks for your help.

8
  • FYI, using .sh extensions for executable scripts (as opposed to shell libraries intended to be invoked with source) is bad form -- executable scripts define commands, and UNIX commands don't have extensions -- they're inherently language-agnostic, as the shebang line at the top defines how they're interpreted. See talisman.org/~erlkonig/documents/… for a longer discussion. Commented Feb 18, 2015 at 1:34
  • (Also, scripts starting with #!/bin/bash are bash scripts, not POSIX sh scripts, so using .sh extensions for them is misleading; many such scripts will break in surprising ways if run with sh somescript, which the extension implies is supported). Commented Feb 18, 2015 at 1:38
  • Thanks for your explanations. So I should save this script as vid2gif, move it to /usr/local/bin folder and run it as 'vid2gif'. Is that right? Commented Feb 18, 2015 at 3:34
  • ...and use chmod +x to mark it executable, yes. If you didn't want to install it for all users, but only for yourself, you might consider making a $HOME/bin directory and adding that to your PATH. Commented Feb 18, 2015 at 13:33
  • The way the title is now written -- looping over files, rather than arguments -- is a little more general, so I've modified section (1) of my answer to suit. Commented Feb 18, 2015 at 14:46

1 Answer 1

2
#!/bin/sh
for f; do
  tempdir=$(mktemp -t -d gifdir.XXXXXX)
  ffmpeg -i "$f" "$tempdir/out%04d.gif"
  gifsicle --delay=10 --loop "$tempdir"/*.gif >"${f%.*}.gif"
  rm -rf "$tempdir"
done

Let's go over how this works:

  1. Iteration

    for f; do
    

    is equivalent to for f in "$@"; that is to say, it loops over all command-line arguments. If instead you wanted to loop over all MP4s in the current directory, this would be for f in *.mp4; do, or to loop over all MP4s named in the directory passed as the first command line argument, it would be for f in "$1"/*.mp4; do. To support either usage -- but go with the first one if no directory is passed -- it would be for f in "${1:-.}"/*.mp4; do.

  2. Temporary directory use

    Because the original script would reuse /tmp/gif for everything, you'd get files from one input source being used in others. This is best avoided by creating a new temporary directory for each input file, which mktemp will automate.

  3. Creating the .gif name

    "${f%.*}" is a parameter expansion which removes everything after the last . in a file; see BashFAQ #100 for documentation on string manipulation in bash in general, including this particular form.

    Thus, "${f%.*}.gif" strips the existing extension, and adds a .gif extension.

Sign up to request clarification or add additional context in comments.

1 Comment

Typically in the location defined by the environment variable TEMPDIR, or /tmp if unset. See man mktemp on your system for precise docs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.