Скрипт Bash: Невозможно выполнить команду mencoder! - PullRequest
0 голосов
/ 21 апреля 2011

вот скрипт ... просто хочу попрактиковаться в навыках bash и быстро использовать утилиту для моего китайского игрока mp4 =)

#!/bin/bash

#####################################
# RockChip 4gb Player mencoder preset
#####################################

TOOL='mencoder'
OUTS='./out/'
OPT1='-noodml'
OPT2="-of avi -ofps 22 -vf-add scale=320:-2,expand=320:240 -srate 44100 -ovc xvid -xvidencopts bitrate=400:max_bframes=0:quant_type=s16le -oac lavc -lavcopts acodec=mp2:abitrate=128"

bold=`tput bold`
normal=`tput sgr0`

# check does argument exists
if test -z "$1"; then
  echo "There's no file given =)"
fi

# Check is it dir or file

if [ -d $1 ]; then
  echo "Directory is given: $1"

  # Test if output argument is given
  if [ -z $2 ]; then
        echo "No output argument given using default: ${bold}${red}$OUTS${normal}"
        mkdir out
  else
      # test is given path a directory
        if [ -d $2 ]; then
                OUT="$2"
        else
           echo "Output argument is not a directory"
        fi
   fi

OLD_IFS=IFS; IFS=$'\n'

for file in `find . -name "*.*" -type f | sed 's!.*/!!'` ; do
        file=`printf "%q" "$file"`
echo    ${TOOL} ${OPT1} ${file} -o ${OUTS}${file} ${OPT2}
done

IFS=OLD_IFS

fi

Проблема в этой строке:

echo    ${TOOL} ${OPT1} ${file} -o ${OUTS}${file} ${OPT2}

Когда вы удаляете echo, чтобы выполнить команду, команда терпит неудачу, но если вы скопируете этот эхо-скрипт и выполните его вручную, все будет работать.

При выполнении команды из сценария оболочки вывод:

MEncoder 1.0rc4-4.2.1 (C) 2000-2010 MPlayer Team
158 audio & 340 video codecs
-of avi -ofps 22 -vf-add scale=320:-2,expand=320:240 -srate 44100 -ovc xvid -xvidencopts bitrate=400:max_bframes=0:quant_type=s16le -oac lavc -lavcopts acodec=mp2:abitrate=128 is not an MEncoder option

Exiting... (error parsing command line)

как я уже говорил перед выполнением команды manualy, все работает, например:

mencoder -noodml 12\ I\ Love\ You\ 1\ \ I\ Love\ You\ 2\ \ I\ Love\ You\ 3.avi -o ./out/12\ I\ Love\ You\ 1\ \ I\ Love\ You\ 2\ \ I\ Love\ You\ 3.avi -of avi -ofps 22 -vf-add scale=320:-2,expand=320:240 -srate 44100 -ovc xvid -xvidencopts bitrate=400:max_bframes=0:quant_type=s16le -oac lavc -lavcopts acodec=mp2:abitrate=128

теперь все, что я могу сделать, это скопировать сгенерированные команды вставки .. в чем проблема? Я очень старался гуглить .. безрезультатно ... (я знаю, что у mencoder есть профили ... это не тот случай, когда я их хочу)

Ответы [ 5 ]

1 голос
/ 21 апреля 2011

Сначала используйте $() вместо обратных тиков.

bold=$(tput bold)
normal=$(tput sgr0)

OLD_IFS=IFS; IFS=$'\n' должно быть OLD_IFS=$IFS. Вы хотите получить значение IFS, поэтому поставьте знак доллара.

Вам не нужно звонить sed, чтобы получить базовое имя файла

while read -r  file
do
    filename="${file##*/}"
    filename=$(printf "%q" $filename)
    echo mencoder "${OPT1}" "${file}" -o "${OUTS}${file}" "${OPT2}"
done < <(find . -name "*.*" -type f)

наконец,

IFS=OLD_IFS должно быть IFS=$OLD_IFS

1 голос
/ 21 апреля 2011

Я не совсем уверен, но, возможно, лучше заключить имя файла в двойные кавычки (") вместо того, чтобы делать printf "%q" "$file".

Так что замените:

file=`printf "%q" "$file"`
${TOOL} ${OPT1} ${file} -o ${OUTS}${file} ${OPT2}

с

${TOOL} ${OPT1} "${file}" -o "${OUTS}${file}" ${OPT2}
1 голос
/ 21 апреля 2011

У вас есть (строка 37, я верю):

OUT="$2"

но я думаю, что вы имели в виду:

OUTS="$2"
0 голосов
/ 21 апреля 2011

Используя ... | xargs bash -c '...', вам просто нужно экранировать одинарные кавычки в имени файла.

TOOL='mencoder'
OUTS='./out/'
OPT1='-noodml'
OPT2='-of avi -ofps 22 -vf-add scale=320:-2,expand=320:240 -srate 44100 -ovc xvid -xvidencopts bitrate=400:max_bframes=0:quant_type=s16le -oac lavc -lavcopts acodec=mp2:abitrate=128'

# test cases
file='12 I Love You 1  I Love You 2  I Love You 3.avi'   
file='12 I Lo"ve You 1  I Love You 2  I Love You 3.avi'   # one embedded double quote
file='12 I Lo"ve You 1  I Lo"ve You 2  I Love You 3.avi'  # two embedded double quotes
file="12 I Lo've You 1  I Love You 2  I Love You 3.avi"   # one embedded single quote
file="12 I Lo've You 1  I Lo've You 2  I Love You 3.avi"  # two embedded single quotes

# escape embedded single quotes in $file
escsquote="'\''"
file="${file//\'/${escsquote}}"

# we're passing ${TOOL} as arg0 to bash -c (which then is available as "$0")
# put the variables in the printf line into single quotes to preserve spaces
# remove no-op ':' to execute the command

printf '%s\n' "${file}"

printf '%s' "${OPT1} '${file}' -o '${OUTS}${file}' ${OPT2}" | 
    xargs bash -c 'set -xv; printf "%s\n" "$0" "$@" | nl' "${TOOL}"

printf '%s' "${OPT1} '${file}' -o '${OUTS}${file}' ${OPT2}" | 
    xargs bash -c 'set -xv; : "$0" "$@"' "${TOOL}"
0 голосов
/ 21 апреля 2011

У вас есть этот оператор перед вашим циклом for:

IFS=$'\n'

Это устанавливает ваш внутренний разделитель полей на новые строки вместо того, чтобы по умолчанию совпадать с любым пробелом.Это меняет способ анализа замещаемых параметров.В строке построения команды:

${TOOL} ${OPT1} ${file} -o ${OUTS}${file} ${OPT2}

произойдет следующее: каждое из этих ${variable} выражений будет расширено, а затем оболочка попытается разбить их на \n, а не на пробел, как выбудет нормально ожидать.Это даст вам результат, аналогичный приведенному ниже (если только одна из этих переменных не содержит символ новой строки):

"${TOOL}" "${OPT1}" "${file}" -o "${OUTS}${file}" "${OPT2}"

Здесь вы можете видеть, что вы передаете всю строку ${OPT2} как однупараметр, вместо того, чтобы позволить Bash разделить его на пробелы и передать каждый флаг в отдельности.mencoder затем запутывается в этом огромном параметре, с которым он не знает, что делать.Конечно, поскольку все пробелы все еще есть, они будут распечатаны командой echo и будут нормально работать в оболочке, в которой $IFS не был сброшен.

Вы можете продемонстрировать этоэффект довольно легко, определяя простую функцию, которая будет печатать каждый из своих аргументов в отдельной строке:

$ print_args() { for arg; do echo $arg; done }
$ foo="1 2"
$ print_args ${foo} ${foo}
1
2
1
2
$ IFS=$'\n'
$ print_args ${foo} ${foo}
1 2
1 2

Я бы рекомендовал не использовать трюк $IFS для вашего цикла for.Вместо этого вы можете использовать while read file для итерации по каждой строке ввода.Я бы также рекомендовал не использовать printf "%q" для экранирования пробелов, а вместо этого просто заключить аргумент в mencoder, который передаст все это как один аргумент.Обратите внимание, что я цитирую ${file} и ${OUTS}${file}, чтобы убедиться, что они передаются в каждом из них как один аргумент, но не цитирую ${OPT1} и ${OPT2}, чтобы их можно было проанализировать как отдельные аргументыракушка.

find . -name "*.*" -type f | sed 's!.*/!!' | while read -r file
do 
    "${TOOL}" ${OPT1} "${file}" -o "${OUTS}${file}" ${OPT2}
done

Кстати, я бы рекомендовал использовать $() для подстановки команд, а не ``;Есть много причин , почему это предпочтительнее, таких как читабельность, более разумное цитирование и экранирование правил внутри него, а также возможность вложения нескольких уровней подстановки команд.И проблемы, на которые указывают Джонатан и Уэс, хорошо отметить, хотя они не являются причиной вашей непосредственной проблемы.

...