Linux Bash脚本不会继续读取文件的下一行

Linux Bash脚本不会继续读取文件的下一行,linux,bash,shell,command-line,scripting,Linux,Bash,Shell,Command Line,Scripting,我有一个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.av

我有一个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
#/bin/bash
#用于读取文件行的Shell脚本实用程序。
#一旦读取该行,它将运行processLine()函数
#函数处理行
processLine(){
行=“$@”
开始=$(日期+%s.%N)
eval$line>/dev/null 2>&1
结束=$(日期+%s.%N)
差异=$(回显“$END-$START”| bc)
echo“$line、$START、$END、$DIFF”>>file.csv 2>&1
echo“花了$DIFF秒”
回音$线
}
#存储文件名
FILE=“”
#获取文件名作为命令行参数
#否则从标准输入设备读取
如果[“$1”=”;然后
FILE=“/dev/stdin”
其他的
FILE=“$1”
#确保文件存在且可读
如果[!-f$文件];然后
echo“$FILE:不存在”
出口1
elif[!-r$文件];然后
echo“$文件:无法读取”
出口2
fi
fi
#使用文件描述符读取$FILE
#将循环分隔符设置为行尾
BAKIFS=$IFS
IFS=$(echo-en“\n\b”)

exec 3我认为这也应该如此,而且似乎是正确的:

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

否?

我会在eval前后添加回声,以查看它将要评估的内容(如果它将整个文件视为一条长线)和之后的内容(如果其中一个ffmpeg命令需要花费很长时间)。

除非您计划在循环后从标准输入读取内容,您不需要保留和恢复原始的标准输入(尽管很高兴看到您知道怎么做)

同样地,我也看不出有什么理由用“如果”来喝酒。在退出之前,当然不需要恢复IFS的值-这是您正在使用的真实shell,而不是DOS BAT文件

当您这样做时:

read var1 var2 var3
shell将第一个字段分配给
$var1
,第二个字段分配给
$var2
,行的其余部分分配给
$var3
。在只有一个变量的情况下——例如,您的脚本——整行都进入变量,就像您希望的那样

在processline函数中,您可能不希望丢弃已执行命令的错误输出。您可能需要考虑检查命令的退出状态。带有错误重定向的
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

我也有同样的问题

我认为ffmpeg应对这种行为负责

我对此问题的解决方案:

1) 在ffmpeg命令行末尾使用“&”调用ffmpeg

2) 因为现在SKIPT不会等到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
#/bin/bash
cat FileList.txt|
读取视频文件时;做
&
FFMPEGStillRunning=“true”
而[“$FFMPEGStillRunning”=“true”];做
进程=$(ps-cfmpeg | grep-o-e“ffmpeg”)
如果[-n“$Process”];然后
FFMPEGStillRunning=“true”
其他的
FFMPEGStillRunning=“false”
fi
睡眠2秒
完成
完成

ffmpeg读取标准数据并将其排出。解决方案是通过以下方式调用ffmpeg:

 ffmpeg </dev/null ...

将IFS设置为“\n\b”不意味着它在空格上断开了吗?我刚刚尝试了“\n”,但它仍然只读取第一行。我不太擅长shell脚本。在processLine中放置一些回音,以查看传入的内容以及处理完成的时间。也许是ffmpeg没有回来。我想你是对的。我将通过手动执行一些命令来检查ffmpeg正在做什么;所以你可以回到工作版本!谢谢你说得更清楚了!:)它仍然只是处理文件的一部分。我想这是因为你!我用各种命令对它进行了测试,结果很好。也许ffmpeg只运行很长的时间?它是否与上一个ffmpeg之后的“它花费了…”相呼应?也许它没有像你想象的那样快?取决于转换,ffmpeg可能会很长。您可以通过不过滤出标准错误来获得进度状态。是的,FFmpeg在某些情况下确实需要一些时间,但shell脚本不应该等到命令完成吗?是的,它读取了一些错误的命令。例如,一些命令被打断“os/mp4/4457kb.mp4/home/test/videos/done/4457kb.flv”-我已经检查文件中是否有换行!或者使用
-nosdin
option@Magne:事实上,这是一个更好的选择。谢谢你恢复了旧的答案,这样我就可以更新它了。
 ffmpeg -nostdin ...