[英]Bash script does not continue to read the next line of file
我有一個 shell 腳本,可以將執行的命令的輸出保存到 CSV 文件中。 它從以下格式的 shell 腳本中讀取必須執行的命令:
ffmpeg -i /home/test/videos/avi/418kb.avi /home/test/videos/done/418kb.flv
ffmpeg -i /home/test/videos/avi/1253kb.avi /home/test/videos/done/1253kb.flv
ffmpeg -i /home/test/videos/avi/2093kb.avi /home/test/videos/done/2093kb.flv
你可以看到每一行都是一個 ffmpeg 命令。 但是,腳本只執行第一行。 就在一分鍾前,它正在執行幾乎所有的命令。 由於某種原因,它丟失了一半。 我編輯了包含命令的文本文件,現在它只會執行第一行。 這是我的 bash 腳本:
#!/bin/bash
# Shell script utility to read a file line line.
# Once line is read it will run processLine() function
#Function processLine
processLine(){
line="$@"
START=$(date +%s.%N)
eval $line > /dev/null 2>&1
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
echo "$line, $START, $END, $DIFF" >> file.csv 2>&1
echo "It took $DIFF seconds"
echo $line
}
# Store file name
FILE=""
# get file name as command line argument
# Else read it from standard input device
if [ "$1" == "" ]; then
FILE="/dev/stdin"
else
FILE="$1"
# make sure file exist and readable
if [ ! -f $FILE ]; then
echo "$FILE : does not exists"
exit 1
elif [ ! -r $FILE ]; then
echo "$FILE: can not read"
exit 2
fi
fi
# read $FILE using the file descriptors
# Set loop separator to end of line
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
exec 3<&0
exec 0<$FILE
while read line
do
# use $line variable to process line in processLine() function
processLine $line
done
exec 0<&3
# restore $IFS which was used to determine what the field separators are
BAKIFS=$ORIGIFS
exit 0
感謝您的任何幫助。
它是 ffmpeg 命令而不是不起作用的 shell 腳本。 但正如保羅指出的那樣,我應該只使用“\b”。 我還利用了 Johannes 的較短腳本。
我認為應該做同樣的事情並且似乎是正確的:
#!/bin/bash
CSVFILE=/tmp/file.csv
cat "$@" | while read line; do
echo "Executing '$line'"
START=$(date +%s)
eval $line &> /dev/null
END=$(date +%s)
let DIFF=$END-$START
echo "$line, $START, $END, $DIFF" >> "$CSVFILE"
echo "It took ${DIFF}s"
done
不?
ffmpeg 讀取 STDIN 並耗盡它。 解決方案是調用 ffmpeg :
ffmpeg </dev/null ...
請參閱此處的詳細說明:http: //mywiki.wooledge.org/BashFAQ/089
更新:
自 ffmpeg 1.0 版以來,還有-nostdin
選項,因此可以改用:
ffmpeg -nostdin ...
我只是有同樣的問題。
我相信 ffmpeg 對這種行為負責。
我對這個問題的解決方案:
1) 在 ffmpeg 命令行的末尾使用“&”調用 ffmpeg
2) 由於現在 skript 不會等到 ffmpeg 進程完成,我們必須防止我們的腳本啟動多個 ffmpeg 進程。 我們通過在至少有一個正在運行的 ffmpeg 進程時延遲循環傳遞來實現這一目標。
#!/bin/bash
cat FileList.txt |
while read VideoFile; do
<place your ffmpeg command line here> &
FFMPEGStillRunning="true"
while [ "$FFMPEGStillRunning" = "true" ]; do
Process=$(ps -C ffmpeg | grep -o -e "ffmpeg" )
if [ -n "$Process" ]; then
FFMPEGStillRunning="true"
else
FFMPEGStillRunning="false"
fi
sleep 2s
done
done
我會在 eval 之前和之后添加 echo 以查看它將要評估的內容(以防它將整個文件視為一大行)和之后(以防 ffmpeg 命令之一永遠執行)。
除非您計划在循環后從標准輸入中讀取某些內容,否則您不需要保留和恢復原始標准輸入(盡管很高興看到您知道如何做)。
同樣,我完全看不到使用 IFS 的理由。 退出前肯定沒有必要恢復 IFS 的值——這是你正在使用的真正的 shell,而不是 DOS BAT 文件。
當你這樣做時:
read var1 var2 var3
shell 將第一個字段分配給$var1
,第二個字段分配給$var2
,並將該行的其余部分分配給$var3
。 在只有一個變量的情況下——例如你的腳本——整行都進入變量,就像你想要的那樣。
在流程線函數內部,您可能不想丟棄已執行命令的錯誤輸出。 您可能確實想考慮檢查命令的退出狀態。 帶有錯誤重定向的echo
是......不尋常的,而且矯枉過正。 如果您非常確定命令不會失敗,那么繼續忽略錯誤。 命令是“健談”嗎? 如果是這樣,請務必停止聊天。 如果不是,也許您也不需要丟棄標准輸出。
當給定多個文件進行處理時,整個腳本可能應該進行診斷,因為它會忽略無關的文件。
您可以僅使用以下方法來簡化文件處理:
cat "$@" |
while read line
do
processline "$line"
done
cat
命令自動報告錯誤(並在錯誤之后繼續)並處理所有輸入文件,或者如果沒有剩余參數則讀取標准輸入。 在變量周圍使用雙引號意味着它作為單個單元傳遞(因此未解析為單獨的單詞)。
date
和bc
的使用很有趣——我以前沒見過。
總而言之,我會看類似的東西:
#!/bin/bash
# Time execution of commands read from a file, line by line.
# Log commands and times to CSV logfile "file.csv"
processLine(){
START=$(date +%s.%N)
eval "$@" > /dev/null
STATUS=$?
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
echo "$line, $START, $END, $DIFF, $STATUS" >> file.csv
echo "${DIFF}s: $STATUS: $line"
}
cat "$@" |
while read line
do
processLine "$line"
done
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.