bash 同步shell脚本执行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1474052/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Synchronize shell script execution
提问by Dave Jarvis
A modified version of a shell scriptconverts an audio file from FLAC to MP3 format. The computer has a quad-core CPU. The script is run using:
shell 脚本的修改版本将音频文件从 FLAC 转换为 MP3 格式。计算机有一个四核 CPU。该脚本使用以下命令运行:
./flac2mp3.sh $(find flac -type f)
This converts the FLAC files in the flacdirectory (no spaces in file names) to MP3 files in the mp3directory (at the same level as flac). If the destination MP3 file already exists, the script skips the file.
这会将flac目录中的 FLAC 文件(文件名中没有空格)转换为mp3目录中的MP3 文件(与 处于同一级别flac)。如果目标 MP3 文件已存在,脚本将跳过该文件。
The problem is that sometimes two instances of the script check for the existence of the same MP3 file at nearly the same time, resulting in mangled MP3 files.
问题是有时脚本的两个实例几乎同时检查同一个 MP3 文件的存在,从而导致 MP3 文件损坏。
How would you run the script multiple times (i.e., once per core), without having to specify a different file set on each command-line, and without overwriting work?
您将如何多次运行脚本(即,每个内核一次),而不必在每个命令行上指定不同的文件集,并且不会覆盖工作?
Update - Minimal Race Condition
更新 - 最小竞争条件
The script uses the following locking mechanism:
该脚本使用以下锁定机制:
# 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;
However, this still leaves a race condition.
然而,这仍然存在竞争条件。
回答by brlcad
The "lockfile" command provides what you're trying to do for shell scripts without the race condition. The command was written by the procmail folks specifically for this sort of purpose and is available on most BSD/Linux systems (as procmail is available for most environments).
“lockfile”命令提供了您在没有竞争条件的情况下尝试为 shell 脚本执行的操作。该命令是由 procmail 人员专门为此目的编写的,可用于大多数 BSD/Linux 系统(因为 procmail 可用于大多数环境)。
Your test becomes something like this:
你的测试变成了这样:
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
Alternatively, you could make lockfile keep retrying indefinitely so you don't need to test the return code, and instead can test for the output file for determining whether to run flac.
或者,您可以让 lockfile 无限期地重试,这样您就不需要测试返回码,而是可以测试输出文件以确定是否运行 flac。
回答by tripleee
If you don't have lockfileand cannot install it (in any of its versions - there are several implementations) a robust and portable atomic mutex is mkdir.
如果您没有lockfile并且无法安装它(在它的任何版本中 - 有几种实现),一个健壮且可移植的原子互斥锁是mkdir.
If the directory you attempt to create already exists, mkdirwill fail, so you can check for that; when creation succeeds, you have a guarantee that no other cooperating process is in the critical section at the same time as your code.
如果您尝试创建的目录已经存在,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
For completeness, maybe also look for flockif you are on a set of platforms where that is reliably made available and need a performant alternative to lockfile.
为了完整起见,flock如果您在一组可靠可用的平台上并且需要lockfile.
回答by michael.d.snider
You could implement locking of FLAC files that it's working on. Something like:
您可以对正在处理的 FLAC 文件实施锁定。就像是:
if (not flac locked)
lock flac
do work
else
continue to next flac
回答by mob
Send output to a temporary file with a unique name, then rename the file to the desired name.
将输出发送到具有唯一名称的临时文件,然后将该文件重命名为所需的名称。
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3.$$"
mv "$MP3.$$" "$MP3"
If a race condition leaks through your file locking system every once in a while, the final output will still be the result of one process.
如果争用条件每隔一段时间通过文件锁定系统泄漏,最终输出仍将是一个进程的结果。
回答by tiian
Use a tool like FLOM (Free LOck Manager)and simply serialize your command as below:
使用像FLOM (Free LOCK Manager)这样的工具,然后简单地序列化您的命令,如下所示:
flom -- flac ....
回答by Byron Whitlock
To lock a file process you can create a file with the same name with a .lock extension.
要锁定文件进程,您可以创建一个带有 .lock 扩展名的同名文件。
Before starting the encoding check the existence of the .lock file, and optionally make sure the date of the lockfile isn't too old (in case the process dies). If it does not exist, create it before the encoding starts, and remove it after the encoding is complete.
在开始编码之前,检查 .lock 文件是否存在,并可选择确保 lockfile 的日期不会太旧(以防进程终止)。如果不存在,在编码开始前创建,编码完成后删除。
You can also flock the file, but this only really works in c where you are calling flock() and writing to the file then closing and unlocking. For a shell script, you probably are calling another utility to do the writing of the file.
您也可以使文件成群结队,但这仅在调用 flock() 并写入文件然后关闭和解锁的 c 中才真正有效。对于 shell 脚本,您可能正在调用另一个实用程序来编写文件。
回答by JesperE
How about writing a Makefile?
写一个Makefile怎么样?
ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
$(FLAC) ...
Then do
然后做
$ make -j4 all
回答by JesperE
In bash it's possible to set noclobber option to avoid file overwriting.
在 bash 中,可以设置 noclobber 选项以避免文件覆盖。
help set | egrep 'noclobber|-C'
帮助集| egrep 'noclobber|-C'

