2011-04-21 207 views
0

下面的脚本..只是想练习一些bash的技能和做出快速util的我的中国MP4播放器=)Bash脚本:无法执行mencoder命令!

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

当您删除回音,以执行命令,命令失败,但如果您将复制此回显脚本,并手动执行它,一切正常。

当从shell脚本输出执行命令:

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的个人资料的..这不是我想要他们的情况下)(37行,我相信)

+1

的分配来OLD_IFS和IFS缺少在RHS一个美元符号,和RHS也应包含在双引号:'OLD_IFS =“$ IFS”; IFS = “$ OLD_IFS”'。但是,由于脚本即将退出,因此重置值无关紧要(因此无论如何也无关紧要)。 – 2011-04-21 04:47:14

回答

0

你有这样的说法您for循环之前:

IFS=$'\n' 

此功能可设置内部字段分隔符换行,而不是默认匹配任何空格。这改变了如何解析替代参数。在构造线命令:

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

会发生什么是每个那些${variable}表达式将扩大,然后shell将尝试拆分他们\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}以允许它们作为单独的参数被shell解析。

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

顺便说一句,我建议你使用$()的命令替换,而不是``;有many reasons为什么它是可取的,例如可读性,更理智的引用和转义规则,以及嵌套多级命令替换的能力。乔纳森和韦斯指出的问题值得注意,尽管它们不是造成你直接问题的原因。

+0

nice thnx mate =)!当我将所有空白文件名与\ n分开时,IFS真的让人头疼。 – holms 2011-04-22 02:06:41

1

您有:

OUT="$2" 

但我认为你的意思是:

OUTS="$2" 
1

我不能完全肯定,但也许这是最好用双引号(")而不是做printf "%q" "$file"引用的文件名。

所以更换:

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

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

首先,使用$()而不是back tick。

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

0

使用... | 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" "[email protected]" | nl' "${TOOL}" 

printf '%s' "${OPT1} '${file}' -o '${OUTS}${file}' ${OPT2}" | 
    xargs bash -c 'set -xv; : "$0" "[email protected]"' "${TOOL}"