Shell 脚本:“如果文件未被使用”条件

Bra*_*ean 5 shell-script files

我正在尝试通过脚本压缩虚拟机映像文件,但我想确保该文件未被访问。我可以检查 virt-manager 是否正在运行,因为它应该是访问图像的唯一程序,但我不知道是否有更好的方法来做到这一点。我还希望脚本继续尝试,直到文件可以压缩为止。我也不知道怎么办。

#Check if virt-manager is running
if pgrep "virt-manager" > /dev/null
then
    #re-run script until success
else
    gzip -k < /home/brady/.vms/windows10/hdd.img > /media/backup/vms/windows10/hdd.$(date +"%F.%T).img.gz
Run Code Online (Sandbox Code Playgroud)

Ste*_*ris 7

lsof命令可以告诉您文件是否正在使用中。你可以把它放在一个while带有 a的循环中,sleep让它每隔一段时间检查一次。

例如:

在窗口 1 中,您可以运行 sleep 10000 > /tmp/x

在窗口 2 中运行此脚本:

#!/bin/bash

FILE=/tmp/x

while [ -n "$(lsof "$FILE")" ]
do
  sleep 1
done

echo "File $FILE not in use"
Run Code Online (Sandbox Code Playgroud)

现在,当您按下control-C中止按钮时,sleep您将在一秒左右内看到“文件未使用”响应。


Sté*_*las 6

在安装了 inotify 工具的 Linux 上,您可以执行以下操作:

#! /bin/zsh -
file=${1?}

# if it's a symlink, we want the real file, readlink also tells us
# if the file is accessible
file=$(readlink -e -- "$file") || exit

# start inotifywait as a coproc so we can terminate it after we're
# done:
coproc LC_ALL=C inotifywait -me close --format . -- "$file" 2>&1

# Now wait for the "Watches established." messaged. First, that allows us
# to verify inotifywait started properly, and that also avoids the race
# condition where the last file user is gone after our fuser check but
# before the watch is in place
read <&p && read <&p && [ "$REPLY" = "Watches established." ] || exit

# Now watch CLOSE events until the file has no more user:
while fuser -s "$file" && read <&p; do continue; done
printf '"%s" is no longer used, renaming it to prevent new access\n' "$file"
kill %
ret=0
if mv -- "$file" "$file.moved-away"; then
  printf 'and now compressing it\n'
  pixz -t < "$file.moved-away" > "$file.xz" || ret=$?
  mv -- "$file.moved-away" "$file" || ret=$? # move back
else
  ret=$?
fi
exit "$ret"
Run Code Online (Sandbox Code Playgroud)

使用inotifywait,每次关闭文件的 fd 时我们都会收到通知。这意味着我们不必经常检查文件,只要最后一个用户关闭文件就可以开始压缩。

请注意,从我的测试来看,与我最初担心的相反,这也适用于 mmapped 文件,因为在这些情况下,CLOSE事件不是close()在最后生成,而是在最后一个munmap()(当文件完全释放时)。

fuser -s检查文件是否打开的方法比lsof. fuser也更有可能可用,因为它是标准的 UNIX 命令(虽然-s不是标准选项,但 Linux 上可用的版本确实支持它)。

我们将文件移开以防止在压缩之前进一步访问。

我们使用pixz(多线程版本的xz,虽然xz现在最新版本也支持多线程),因为它提供了比 gzip 更好的压缩率,更重要的是,因为压缩文件是随机访问的(您可以挂载内容或引导它在使用 nbdkit 的 VM 中,而无需解压缩整个图像)。

注意,相似的lsoffuser将不会检测到文件被用作loopmtd设备后端。对于循环设备,您可以losetup -j "$file"用来检查文件是否正在以这种方式使用。例如,您可以在文件移开后插入此循环:

while [ -n "$(losetup -j "$file.moved-away")" ]; do
  sleep 1
done
Run Code Online (Sandbox Code Playgroud)