2

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.

rnso
  • 23,686
  • 25
  • 112
  • 234
  • this might help https://unix.stackexchange.com/questions/131766/why-does-my-shell-script-choke-on-whitespace-or-other-special-characters – Sundeep May 11 '17 at 06:18
  • I don't exactly understand your question but it seems you need to use **getopt** or **getopts**. http://stackoverflow.com/questions/16483119/example-of-how-to-use-getopts-in-bash http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash – Theofanis May 11 '17 at 06:19
  • Thanks everyone for your very useful answers. I am trying these and will post the feedback. – rnso May 11 '17 at 08:25

4 Answers4

3

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
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
1

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
Allan Karlson
  • 453
  • 11
  • 23
1

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...

gboffi
  • 22,939
  • 8
  • 54
  • 85
1

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"
ceving
  • 21,900
  • 13
  • 104
  • 178
  • 1
    It should be `dst=$1` and not $2 (since shift has been used). Otherwise it works perfectly. – rnso May 11 '17 at 13:41