2011-04-21 251 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}"