shell scripting escape madness - enviando aspas simples para subshell

0

Estou além do meu nível de habilidade para fazer isso funcionar corretamente ...

#!/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

este script atualmente ecoa o comando ffmpeg com formatação perfeita, mas não consigo executá-lo. Ele sempre reclama com um erro sobre "Argumento inválido".

Basicamente, eu preciso passar um monte de caracteres de aspas simples no comando que vai para o subshell.

O produto final a ser enviado para a subshell é assim:

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'

Editar:

Ok ... deixa pra lá .... Entendi ... obrigado por ouvir. E para quem está procurando pegar arquivos de uma câmera de vídeo (que automaticamente segmenta os arquivos) e juntá-los ou concatená-los em um vídeo contínuo usando o ffmpeg, aqui está um 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
    
por user36414 03.04.2013 / 17:02

1 resposta

1

Você não pode armazenar uma lista de nomes de arquivos em inputs desta maneira: inputs é uma string, você não pode distinguir os espaços e ' que vêm de um nome de arquivo e os que você adicionou para a cadeia. A propósito, inputs="$inputs -i ""'""$file""'" é uma maneira confusa de escrever inputs="$inputs -i '$file'" (ou seja, acrescentar um espaço, -i , um espaço, uma aspa simples, o nome do arquivo e outra aspa simples).

Seu comando echo imprime um comando shell válido porque você tentou em nomes de arquivos que não contêm caracteres especiais (em particular, sem aspas simples - com relação à parte $inputs , todos os outros caracteres seriam ok ). Sem echo , você está executando

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\'

(simplifiquei as aspas redundantes). Observe como toda a string até [a1] [a2] é um único argumento.

Para armazenar vários argumentos para um comando, use uma matriz. Quando você executa o comando, use aspas duplas em torno de todas as substituições de variáveis ( "$foo" ou para uma matriz "${foo[@]}" ). Não coloque aspas ao redor daspas, caso contrário você está passando o caractere de aspas literal para o comando ffmpeg .

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 que você não está passando nenhuma aspas simples para qualquer subshell (você nem está executando um subshell). As citações estão lá para a análise do seu script, sem citações são passadas para qualquer comando.

    
por 04.04.2013 / 03:20