shell script的修改版本将音频文件从FLAC转换为MP3格式。该计算机具有四核CPU。该脚本使用以下命令运行:
./flac2mp3.sh $(find flac -type f)
这会将flac
目录中的FLAC文件(文件名中没有空格)转换为mp3
目录中的MP3文件(与flac
处于同一级别)。如果目标MP3文件已存在,则脚本会跳过该文件。
问题是,有时两个脚本实例几乎同时检查是否存在相同的MP3文件,导致MP3文件损坏。
如何多次运行脚本(即每个核心运行一次),而不必在每个命令行上指定不同的文件集,而不覆盖工作?
更新 - 最小竞争条件
该脚本使用以下锁定机制:
# Convert FLAC to MP3 using tags from flac file.
#
if [ ! -e $FLAC.lock ]; then
touch $FLAC.lock
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
rm $FLAC.lock
fi;
然而,这仍然存在竞争条件。
答案 0 :(得分:6)
“lockfile”命令提供了在没有竞争条件的情况下尝试为shell脚本执行的操作。该命令由procmail人员专门为此目的编写,并且可在大多数BSD / Linux系统上使用(因为procmail适用于大多数环境)。
您的测试会变成这样:
lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
fi
rm -f $FLAC.lock
或者,您可以使lockfile保持无限期重试,这样您就不需要测试返回代码,而是可以测试输出文件以确定是否运行flac。
答案 1 :(得分:3)
如果您没有lockfile
并且无法安装(在其任何版本中-有多种实现方式),则健壮且可移植的原子互斥体为mkdir
。
如果您尝试创建的目录已经存在,则mkdir
将失败,因此您可以进行检查;创建成功后,您可以确保在代码的关键部分没有其他协作过程同时存在。
if mkdir "$FLAC.lockdir"; then
# you now have the exclusive lock
: critical section
: code goes here
rmdir "$FLAC.lockdir"
else
: nothing? to skip this file
# or maybe sleep 1 and loop back and try again
fi
出于完整性考虑,如果您使用的一组平台可靠地可用,并且需要替代flock
的高性能平台,则可能还会寻找lockfile
。
答案 2 :(得分:1)
您可以实现锁定正在处理的FLAC文件。类似的东西:
if (not flac locked)
lock flac
do work
else
continue to next flac
答案 3 :(得分:1)
将输出发送到具有唯一名称的临时文件,然后将文件重命名为所需名称。
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3.$$"
mv "$MP3.$$" "$MP3"
如果竞争条件每隔一段时间通过您的文件锁定系统泄漏,最终输出仍然是一个过程的结果。
答案 4 :(得分:0)
要锁定文件进程,您可以创建一个名称与.lock扩展名相同的文件。
在开始编码之前检查.lock文件是否存在,并且可选地确保lockfile的日期不是太旧(如果进程死亡)。如果它不存在,请在编码开始之前创建它,并在编码完成后将其删除。
你也可以植入文件,但这只适用于你调用flock()并写入文件然后关闭和解锁的c。对于shell脚本,您可能正在调用另一个实用程序来编写文件。
答案 5 :(得分:0)
编写Makefile怎么样?
ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
$(FLAC) ...
然后做
$ make -j4 all
答案 6 :(得分:0)
在bash中,可以设置noclobber选项以避免文件覆盖。
帮助设置| egrep'noclobber | -C'
答案 7 :(得分:0)
使用像FLOM (Free LOck Manager)这样的工具,只需将命令序列化如下:
flom -- flac ....