簡體   English   中英

Bash 腳本不繼續讀取文件的下一行

[英]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

感謝您的任何幫助。

更新 2

它是 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命令自動報告錯誤(並在錯誤之后繼續)並處理所有輸入文件,或者如果沒有剩余參數則讀取標准輸入。 在變量周圍使用雙引號意味着它作為單個單元傳遞(因此未解析為單獨的單詞)。

datebc的使用很有趣——我以前沒見過。

總而言之,我會看類似的東西:

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM