我通过 Lutris 安装了《魔兽争霸 3》,从 /Download/ 复制自定义地图很麻烦,所以我写了一个脚本来帮我做到这一点。
问题是
inotifywait
应该等到下载(我不确定它在技术上是移动、创建还是写入)完成,然后将文件处理到脚本的其余部分,但事实并非如此。当我单击“下载”时,会创建一个 0 字节文件,脚本会立即拾取并复制该文件,然后高兴地宣布它成功了。
除了睡眠之外,如何让它等待文件写入/下载/移动完成?我对睡眠犹豫不决,因为我不知道即将到来的文件的文件大小和下载速度。
我确实找到了关于我的问题的这篇文章: bash 脚本 inotifywait 等待文件完全写入后再继续 它不能解决我的问题,因为 close_write 不会阻止它将空文件移交给要复制的脚本的其余部分。它要么不等待文件关闭进行写入,要么下载不写入。
我写了以下脚本:
#!/bin/bash
#This script runs at startup and watches \~/Downloads. When it finds a \*.w3x file, it checks ./Games/battlenet/drive_c/users/user/Documents/Warcraft III/Maps/Download/ and if the file isn't there, it copies it there and then deletes the original from \~/Downloads
#Directory to be watched
DIR_TO_WATCH="$HOME/Downloads/"
#Directory to copy the files to
DEST_DIR="$HOME/Games/battlenet/drive_c/users/user/Documents/Warcraft III/Maps/Download/"
#Run inofifywait and wait for a CLOSE event which occures when a file was open for writing (e.g.: modifying, being copied, being downloaded, etc) and then the scrpit will check if the change fits this it's conditions. Whatever the outcome is, it will get pushed to the processing below with the '|' symbol
inotifywait -m "$DIR_TO_WATCH" -e close |
#Processing events. Every line of events if there are multiple
while read path action file
do
#Check if there is a Warcraft 3 map
if [[ "$file" == *.w3x ]];
then
#Check if the file already exists in the WC3 Download folder specified in DEST_DIR
if [ ! -f "$DEST_DIR/$file" ];
then
echo "NEW TRANSACTION ---$(date)---" >> wc3_mapsync.log
echo "$(date) | $file size before copy: $(stat -c%s "$path$file")" >> wc3_mapsync.log
cp "$path$file" "$DEST_DIR"
if [ $? -eq 0 ]
then echo "$(date) | $file COPIED SUCCESSFULLY $path$file >>> $DEST_DIR" >> wc3_mapsync.log
echo "$(date) | $file size after copy: $(stat -c%s "$DEST_DIR/$file")" >> wc3_mapsync.log
echo "---END TRANSACTION---" >> wc3_mapsync.log
rm "$path$file"
else echo "$(date) | $file COPY FAILED with exit status code $? '|' $path$file" >> wc3_mapsync.log
echo "---END TRANSACTION---" >> wc3_mapsync.log
fi
else
echo "$(date) | $file ALREADY EXITSTS, copy would be duplicate." >> wc3_mapsync.log
echo "---END TRANSACTION---" >> wc3_mapsync.log
fi
else :
fi
done
根据我收到的评论,我修复了它,具体方法如下:
我采纳了 Charles Duffy 的建议并进行了修改。您是对的,下载是在脚本的输出所确认的部分进行的。我扔掉了我的注释,修剪了代码,并将 sleep 放置到了正确的位置,我认为它在关闭写入后读取文件名,等待(所以如果写入发生在下载等部分,它可以继续,重置周期),然后执行第二部分:
#!/bin/bash
#要观看的目录 DIR_TO_WATCH="$HOME/下载/"
#将文件复制到的目录 DEST_DIR="$HOME/Games/battlenet/drive_c/users/hori/Documents/Warcraft III/Maps/Download/"
inotifywait -m“$DIR_TO_WATCH”-e close_write |
while read path action file
do
sleep 2
if [[ "$file" == *.w3x ]];
then
if [ ! -f "$DEST_DIR/$file" ];
then
cp "$path$file" "$DEST_DIR"
fi
fi
done
P.s.:我不知道为什么编辑器不将 #!/bin/bash 视为代码的开头