Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm beyond my skill level in getting this to work properly...

#!/bin/bash -x
# mxfbc.sh - mxf video file batch converter
# pass at the command line ...
# (1) the directory to batch convert (typically called CLIPS00X from the Canon XF100 and, 
# (2)the file type to convert (typically MXF from the Canon XF100)

# updated 2012-Feb-18

CLIPS_dir="$1"
type="$2"


function ffconvert()
{
#   ffmpeg -i "$1"  -r 30 -f mov -vcodec libx264 -acodec pcm_s16le -map 0:0 -map 0:1 -map 0:2 "${1%%.*}"\.MOV
    ffmpeg -i "$1"  -r 30 -f mov -vcodec libx264 -acodec copy -threads 0 -map 0:0 -map 0:1 -acodec copy -map 0:2 -acodec copy "${1%%.*}"\.MOV
#   ffmpeg -i "$1"  -r 30 -f mov -vcodec copy -acodec pcm_s16le -map 0:0 -map 0:1 -map 0:2 "${1%%.*}"\.MOV
}
#12

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

date
for item in $CLIPS_dir* ; do

if [ -d $item ]; then

    inputs=""
    map=""
    count=0
         #echo -e "Item: $item"
            for file in $item/* ; do

                if [ ${file#*.} = "$type" ]; then
                    #date
                    #echo -e "Now processing: ${file##*/} \n"
                    #echo "File name: ${file%%.*}"
                    #echo "File type: ${file##*.}"
                    #inputs="$inputs -i ${file##*/}"
                    inputs="$inputs -i ""'""$file""'"
                    map="$map[$count:0] [$count:1] [$count:2] "
                    count=$(($count+1)) 

                    # ffconvert "$CLIPS_dir$item/$file"
            #       echo -e "Finished processing: ${file##*/} \n"

                fi
            done
            filter=$map
            #echo -e $inputs
            echo -e $count
            #echo -e $map
            #echo -e $filter


echo ffmpeg "$inputs"" -r 29.97 -f mov -vcodec libx264 -acodec pcm_s16le -threads 0 -filter_complex ""'""$filter""concat=n=""$count"":v=1:a=2 [v] [a1] [a2]'" -map \'[v]\' -map \'[a1]\' -map \'[a2]\' "'""$item"\.MOV"'"
fi

done



# restore $IFS
IFS=$SAVEIFS

this script currently echos the ffmpeg command with perfect formatting, but I can't get it to execute the command. It always complains with an error about "Invalid Argument".

Basically, I need to pass a lot of single quote characters in the command that goes to the subshell.

The final product to send to subshell looks like this:

ffmpeg  -i '/Volumes/localtank/card2/CONTENTS/CLIPS001/AA0715/AA071501.MXF' -i '/Volumes/localtank/card2/CONTENTS/CLIPS001/AA0715/AA071502.MXF' -i '/Volumes/localtank/card2/CONTENTS/CLIPS001/AA0715/AA071503.MXF' -i '/Volumes/localtank/card2/CONTENTS/CLIPS001/AA0715/AA071504.MXF' -i '/Volumes/localtank/card2/CONTENTS/CLIPS001/AA0715/AA071505.MXF' -r 29.97 -f mov -vcodec libx264 -acodec pcm_s16le -threads 0 -filter_complex '[0:0] [0:1] [0:2] [1:0] [1:1] [1:2] [2:0] [2:1] [2:2] [3:0] [3:1] [3:2] [4:0] [4:1] [4:2] concat=n=5:v=1:a=2 [v] [a1] [a2]' -map '[v]' -map '[a1]' -map '[a2]' '/Volumes/localtank/card2/CONTENTS/CLIPS001/AA0715.MOV'

Edit:

Ok... nevermind .... Got it... thanks for listening. And for anyone who is looking to take files from a video camera (which automatically segments the files) and rejoin or concatenate them into a continuous video using ffmpeg, here's a script. ...

#!/bin/bash -x
# mxfbcc.sh - mxf video file batch converter and concatenate parts into a whole
# pass at the command line ...
# (1) the directory to batch convert (typically called CLIPS00X from the Canon XF100 and, nothing else

# updated 2013-April-3

CLIPS_dir="$1"


function ffconvert()
{
#   ffmpeg -i "$1"  -r 30 -f mov -vcodec libx264 -acodec pcm_s16le -map 0:0 -map 0:1 -map 0:2 "${1%%.*}"\.MOV

    ffmpeg -i "$1"  -r 30 -f mov -vcodec libx264 -acodec copy -threads 0 -map 0:0 -map 0:1 -acodec copy -map 0:2 -acodec copy "${1%%.*}"\.MOV
#   ffmpeg -i "$1"  -r 30 -f mov -vcodec copy -acodec pcm_s16le -map 0:0 -map 0:1 -map 0:2 "${1%%.*}"\.MOV

}
#12

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

date
for item in $CLIPS_dir* ; do

if [ -d $item ]; then

    inputs=""
    map=""
    count=0
         #echo -e "Item: $item"
            for file in $item/* ; do

                if [ ${file#*.} = "MXF" ]; then
                    #date
                    #echo -e "Now processing: ${file##*/} \n"
                    #echo "File name: ${file%%.*}"
                    #echo "File type: ${file##*.}"
                    #inputs="$inputs -i ${file##*/}"
                    input+="-i '${file}' "
                    map="$map[$count:0] [$count:1] [$count:2] "
                    count=$(($count+1)) 

                    # ffconvert "$CLIPS_dir$item/$file"
            #       echo -e "Finished processing: ${file##*/} \n"

                fi
            done
            filter=$map
            #echo -e $inputs
            #echo -e $count
            #echo -e $map
            #echo -e $filter
            #echo -e 


eval ffmpeg ${input} -r 29.97 -f mov -vcodec libx264 -acodec pcm_s16le -threads 0 -filter_complex \'$filter concat=n=$count:v=1:a=2 [v] [a1] [a2]\' -map \'[v]\' -map \'[a1]\' -map \'[a2]\' \'$item\.MOV\'
fi

done



# restore $IFS
IFS=$SAVEIFS
share|improve this question
    
"Invalid Argument" sounds like a problem with ffmpeg rather than with the shell, which would complain along the lines of unexpected EOF while looking for matching `''. What makes you think the single quotes are the problem? –  l0b0 Apr 3 '13 at 15:27
    
There seems to be an unbalanced double quote "$inputs"" in your "perfectly formatted" output. –  jlliagre Apr 3 '13 at 15:48
    
and please strip off all the useless comments from your script for a better readability. –  jlliagre Apr 3 '13 at 15:50
    
Well, I knew it was perfectly formatted because I could copy the echoed command and paste it back onto the command line and it would run properly. The double quote that balances the one you found is farther down... –  user36414 Apr 3 '13 at 15:50
add comment

1 Answer

You can't store a list of file names in inputs this way: inputs is a string, you can't distinguish the spaces and ' that come from a file name and the ones that you added to the string. By the way, inputs="$inputs -i ""'""$file""'" is a confusing way of writing inputs="$inputs -i '$file'" (i.e. append a space, -i, a space, a single quote, the file name, and another single quote).

Your echo command prints a valid shell command because you tried it on file names that don't contain special characters (in particular, no single quotes — with respect to the $inputs part, all other characters would be ok). Without echo, you're running

ffmpeg "$inputs -r 29.97 -f mov -vcodec libx264 -acodec pcm_s16le -threads 0 -filter_complex '${filter}concat=n=$count:v=1:a=2 [v] [a1] [a2]'" \
       -map \'[v]\' -map \'[a1]\' -map \'[a2]\' \'$item\.MOV\'

(I simplifed the redundant quotes). Notice how the whole string up to [a1] [a2] is a single argument.

To store multiple arguments for a command, use an array. When you run the command, use double quotes around all variable substitutions ("$foo", or for an array "${foo[@]}"). Don't put quotes around quotes, otherwise you're passing the literal quote character to the ffmpeg command.

inputs=()
…
    inputs+=(-i "$file")
…
ffmpeg "${inputs[@]}" -r 29.97 -f mov \
       -vcodec libx264 -acodec pcm_s16le -threads 0 \
       -filter_complex "${filter} concat=n=$count:v=1:a=2 [v] [a1] [a2]" \
       -map '[v]' -map '[a1]' -map '[a2]' "$item.MOV"

Note that you aren't passing any single quotes to any subshell (you're not even running a subshell). The quotes are there for the parsing of your script, no quotes are passed to any command.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.