rnso
rnso

Reputation: 24535

Script to act on multiple files in Linux

I want to create a script that can be given 3 arguments: task, infile-type, outfile-type; and it should apply the task to each of such files in the folder. For example, I should be able to give command: convert png jpg, and it should convert all png files to jpg in the folder. I should also be able to send options with task, enclosed in quotes, e.g.: "convert -o myoption" png jpg

I tried:

#! /bin/bash
for f in *.$2
  do 
    $1 "$f" -o "${f%.$2}.$3"
  done

Will above work or do I need to enclose $1 etc in {} or []? I have not tried it since, if erroneous, it may cause unpredictable damage to files. Thanks for your help.

Upvotes: 2

Views: 454

Answers (4)

ceving
ceving

Reputation: 23824

Move the command to the end of your argument list.

#! /bin/bash
src=$1; shift
dst=$1; shift
for f in *."$src"
do 
  "$@" "$f" -s -o "${f%.$src}.$dst"
done

Then the arguments get correctly quoted

my-script png jpg convert -o myoption

even, if the arguments contain spaces.

my-script png jpg convert --some-option "argument with spacees"

Upvotes: 1

Mark Setchell
Mark Setchell

Reputation: 207465

You can express that quite readily with GNU Parallel and have the added benefit of all the tasks being run in parallel too:

parallel convert {} {.}.png ::: *.jpg

where {} replaces the argument and {.} represents the argument without extension.

As regards your concern for doing something potentially dangerous, use --dry-run to test out what it would do, without actually doing anything:

parallel --dry-run convert -o XYZ {} {.}.png ::: *.jpg

Sample Output

convert -o XYZ a.jpg a.png
convert -o XYZ a\ g.jpg a\ g.png
convert -o XYZ b.jpg b.png

Upvotes: 3

gboffi
gboffi

Reputation: 25023

An useful technique while writing shell scripts that may have dangerous results simply consists in using the echo builtin.

Your code is substantially correct, I'd just use a bit of extra quoting and a test to exclude the possibility of action on non existing files (even if this is more cosmetic...)

repeat() { for f in *.$2 ; do
    [ -f "$f" ] && echo $1 \"$f\" \"${f%.$2}.$3\"
  done ; }

Here it is a short terminal session to show how it works

$ ls
a b.png  a.png  b.png
$ repeat() { for f in *.$2 ; do [ -f "$f" ] && echo $1 \"$f\" \"${f%.$2}.$3\" ; done ; }
$ repeat 'cp -f' pmg jpg     #### typinh error
$ repeat 'cp -f' png jpg
cp -f "a b.png" "a b.jpg"
cp -f "a.png" "a.jpg"
cp -f "b.png" "b.jpg"
$ repeat 'cp -f' png jpg | sh
$ ls
a b.jpg  a b.png  a.jpg  a.png  b.jpg  b.png
$ 

When you are 99.9% sure of your code, remove the echo and there you are...

Upvotes: 1

Allan Karlson
Allan Karlson

Reputation: 499

I guess you want to have a list of files in your folder. You may try that. Let me now if there are some errors so I may can change it to what you exactly want

#! /bin/bash

# Command which should performed
echo $1
# File type IN
echo $2
# File type OUT
echo $3

for i in $(ls)
do

    $1 $2 $3 $i
done

Upvotes: 1

Related Questions