# shell script strangeness



## jalla (Feb 8, 2010)

I made a small script to convert some mpegs to a more portable format


```
#!/bin/sh

usage () {
	echo "usage: $0 [-f file] [-dvh]"
}

help () {
	usage
	echo " -f <file>
 -d     dryrun
 -v     verbose
 -h     help
"
exit
}
trap "exit 1" 0 1 2 15

system () {
  test -z $verbose || echo "+ $*" 1>&2
  test -z $dryrun || return
  eval "$@"
}
while [ x"$1" != x"" ]
do
	case  $1 in
		-f)             file=$2; shift;;
		-v)             verbose=1;;
		-d)             dryrun=1;;
		-h)             help;exit;;
	esac
	shift
done

test -z "$file" && help;
test -f "$file" || help

grep -v '^#' $file | \
while read a b 
do
 	cmd="fmpeg -i $a -ac 2 -ar 48000 -b 1000k -s cif $b.m4v"
	system $cmd
done
```

I feed the script with a file like this


```
gong:/medialib/tc# cat infile.txt
#/medialib/teapot/3150_20091012215900.mpg file-1
/medialib/teapot/2150_20091026215900.mpg file-2
/medialib/teapot/3150_20091102215900.mpg file-3
/medialib/teapot/3150_20091110215900.mpg file-4
```

Testrun


```
gong:/medialib/tc# ./trans.sh -v -d -f infile.txt 
+ fmpeg -i /medialib/teapot/2150_20091026215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-2.m4v
+ fmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-3.m4v
+ fmpeg -i /medialib/teapot/3150_20091110215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-4.m4v
```

However when I ommit '-d', ffmpeg runs only once and then the script exits silently


```
gong:/medialib/tc# ./trans.sh -f infile.txt -v 
+ fmpeg -i /medialib/teapot/2150_20091026215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-2.m4v
FFmpeg version 0.5, Copyright (c) 2000-2009 Fabrice Bellard, et al.

 .... plenty of output as ffmpeg does it's job

gong:/medialib/tc#
```

Does anyone see something obviously stupid I'm doing, or otherwise have an explanation for this behaviour?


----------



## SirDice (Feb 8, 2010)

The bourne shell doesn't have a 'system' command. Remove the 'system' from your script.

Scratch that, I didn't notice the function. I'm betting the error is in there though. 

Looks like the 'test -z $dryrun || return' doesn't do what you expect


----------



## jalla (Feb 8, 2010)

Funny thing is, if I replace ffmpeg with a bogus cmd it does loop

```
gnome:/medialib/tc# ./trans.sh -v -f infile.txt 
+ fmpeg -i /medialib/teapot/2150_20091026215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-2.m4v
fmpeg: not found
+ fmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-3.m4v
fmpeg: not found
+ fmpeg -i /medialib/teapot/3150_20091110215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-4.m4v
fmpeg: not found
```

And, btw `-d` work as expected, witness this

```
gnome:/medialib/tc# ./trans.sh -v -f infile.txt -d
+ fmpeg -i /medialib/teapot/2150_20091026215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-2.m4v
+ fmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-3.m4v
+ fmpeg -i /medialib/teapot/3150_20091110215900.mpg -ac 2 -ar 48000 -b 1000k -s cif file-4.m4v
```


----------



## SirDice (Feb 8, 2010)

jalla said:
			
		

> And, btw `-d` work as expected, witness this


Now have another close look at your code.. See what happens when $dryrun isn't defined


----------



## aragon (Feb 8, 2010)

Are you pasting us the same script?  What you pasted seems to work here...


----------



## jalla (Feb 8, 2010)

aragon said:
			
		

> Are you pasting us the same script?  What you pasted seems to work here...



100%
I pasted it back and compared them.

As it happens the script works with anything I throw at it except ffmpeg.


----------



## jalla (Feb 8, 2010)

SirDice said:
			
		

> Now have another close look at your code.. See what happens when $dryrun isn't defined



When $dryrun isn't defined the cmd is executed. Just the way I want it.


----------



## SirDice (Feb 8, 2010)

You can always run your shell script with the -x option. I use it quite a lot to see what's going on.


----------



## jalla (Feb 8, 2010)

SirDice said:
			
		

> You can always run your shell script with the -x option. I use it quite a lot to see what's going on.



Good point. Unfortunately it makes me none the wiser. Here's the end of a run with -x. It shows a normal end of the ffmpeg cmd, then the next iteration of the while loop (read a b), and then an immediate exit 1.


```
...
[libx264 @ 0x806548a10]slice I:12747 Avg QP:20.52  size: 17168
[libx264 @ 0x806548a10]slice P:140164 Avg QP:22.32  size:  3990
[libx264 @ 0x806548a10]mb I  I16..4:  7.7%  0.0% 92.3%
[libx264 @ 0x806548a10]mb P  I16..4:  3.4%  0.0%  0.0%  P16..4: 83.6%  0.0%  0.0%  0.0%  0.0%    skip:13.0%
[libx264 @ 0x806548a10]final ratefactor: 16.60
[libx264 @ 0x806548a10]SSIM Mean Y:0.9747017
[libx264 @ 0x806548a10]kb/s:1017.8
+ read a b
+ exit 1
```


----------



## DutchDaemon (Feb 8, 2010)

Well, go all out with `sh -xv`.


----------



## aragon (Feb 8, 2010)

Remove the trap.  There shouldn't be a trap on signal 0.  I guess that is causing Strange Things to occur...


----------



## aragon (Feb 8, 2010)

Sorry, I think it might actually be your trap on signal 2 that's causing this.  Anyhow, experiment with that line as it's the only place where "exit 1" can be getting called.


----------



## jalla (Feb 9, 2010)

aragon said:
			
		

> Sorry, I think it might actually be your trap on signal 2 that's causing this.  Anyhow, experiment with that line as it's the only place where "exit 1" can be getting called.



No it's not the trap, but I nailed it in the end anyway. It's actually ffmpeg that eats the rest of infile.
Remember when ffmpeg starts processing it says

`Press [q] to stop encoding`

The problem is clearly demonstrated with a slightly modified infile (add some q's in there)


```
#/medialib/teapot/3150_20091012215900.mpg qfile-1
#/medialib/teapot/2150_20091026215900.mpg qfile-2
/medialib/teapot/3150_20091102215900.mpg qfile-3
/medialib/teapot/3150_20091110215900.mpg qfile-4
```

Then another run of the script (with ffmpeg output redirected for clarity)


```
gong:/medialib/tc# sh -x trans.sh -f infile.txt
+ [ x-f != x ]
+ file=infile.txt
+ shift
+ shift
+ [ x != x ]
+ test -z infile.txt
+ test -f infile.txt
+ grep -v '^#' infile.txt
+ read a b
+ cmd='ffmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y qfile-3.m4v > qfile-3.out 2>&1'
+ system ffmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y qfile-3.m4v '>' qfile-3.out '2>&1'
+ test -z
+ test -z
+ eval ffmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y qfile-3.m4v '>' qfile-3.out '2>&1'
+ ffmpeg -i /medialib/teapot/3150_20091102215900.mpg -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y qfile-3.m4v
+ read a b
+ cmd='ffmpeg -i file-4 -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y .m4v > .out 2>&1'
+ system ffmpeg -i file-4 -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y .m4v '>' .out '2>&1'
+ test -z
+ test -z
+ eval ffmpeg -i file-4 -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y .m4v '>' .out '2>&1'
+ ffmpeg -i file-4 -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y .m4v
+ read a b
gong:/medialib/tc#
```

The first invocation of ffmpeg continues to read characters from stdin up to the first 'q' and quits. Then the next round of the loop reads whats left, which is only 'file4'.

So the while-loop has to go. Here's a replacement to make the script work


```
IFS='
'
for l in `grep -v '^#' $file`
do
        a=`echo $l | cut -d " " -f 1`
        b=`echo $l | cut -d " " -f 2`
        cmd="ffmpeg -i $a -ac 2 -ar 48000 -b 1000k -s cif -t 60 -y $b.m4v > $b.out 2>&1"
        system $cmd
done
```


----------

