同步shell脚本执行

时间:2009-09-24 20:46:31

标签: linux bash shell multiprocessing race-condition

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;

然而,这仍然存在竞争条件。

8 个答案:

答案 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 ....