1

我正在尝试将 Linux bash 脚本移植到 FreeBSD。该脚本需要在决定是否采取某些操作之前检查文件是否打开(用于写入)。

在 Linux 上,这很容易使用以下fuser命令:

if [[ ! `/usr/bin/fuser "$FILE"` ]]
     then
     ...
fi

然而,在 FreeBSD 上,该fuser命令似乎完全被破坏了(由this证明)并且没有返回任何正确的退出代码或任何有用的输出到标准输出。例如,在一个正在被主动写入的文件上:

# fuser file 
file:

编辑:


弗拉基米尔·博特卡的评论:

“FreeBSD 12.0 中的简单测试显示”:

# tail -f /scratch/test-file`
# fuser /scratch/test-file
/scratch/test-file: 45042
# echo $?
0
# ps ax | grep 45042
45042  0  I+       0:00.00 tail -f /scratch/test-file
45232  1  R+       0:00.00 grep 45042

在我的 FreeBSD 机器(也是 FreeBSD 12)上,相同的测试产生以下结果:

# tail -f /scratch/test-file
# fuser /scratch/test-file
/scratch/test-file:
# echo $?
0

弗拉基米尔·博特卡的评论:

让我们尝试使用一个简单的 C 程序来测试对文件的写入,该程序打开文件,等待输入并将输入写入文件。

这是我对编译后的 C 代码的测试:

# ./a.out
Enter num:

# fuser /scratch/test-file
/scratch/test-file:
# echo $?
0

因此,fuser似乎确实被打破了。但是,它似乎只在我的系统上坏了,而不是在 Vladimir Botka 的系统上,这很奇怪,因为它们都是 FreeBSD 12。


看来我可以使用lsoffstat获取这些信息,但不能不对输出进行一些复杂的解析,这会使我的脚本更加复杂。我想知道是否有人可以向我指出一个简单的“是/否”命令来确定一个文件是否正在使用中,这样的文件是否fuser可以在 FreeBSD 上运行?

非常感谢,

4

4 回答 4

2

您的索赔

“在 FreeBSD 上 fuser 命令似乎完全损坏了”

端口详细信息:用于 FreeBSD 的 fuser POSIX fuser 实用程序,已弃用并过期:2012-11-26

让我们在 FreeBSD 12.0 中尝试这个简单的测试。打开终端并运行

# touch /scratch/test-file
# tail -f /scratch/test-file

保持tail等待test-file的内容。打开第二个终端并运行

# fuser /scratch/test-file
/scratch/test-file: 45042
# echo $?
0
# ps ax | grep 45042
45042  0  I+       0:00.00 tail -f /scratch/test-file
45232  1  R+       0:00.00 grep 45042

让我们尝试使用一个简单的 C 程序来测试对文件的写入,该程序打开文件,等待输入并将输入写入文件。

#include <stdio.h>
#include <stdlib.h>
int main()
{
   int num;
   FILE *fptr;
   fptr = fopen("/scratch/test-file","w");
   printf("Enter num: ");
   scanf("%d",&num);
   fprintf(fptr,"%d",num);
   fclose(fptr);
   return 0;
}

# ./a.out 
Enter num: 

让程序等待输入。打开第三个终端并运行

# fuser /scratch/test-file
/scratch/test-file: 45448w 45042
# echo $?
0
# ps ax | grep 45448
45448  0  I+       0:00.00 ./a.out
45464  1  S+       0:00.00 grep 45448

如果打开文件以写入fuser将“w”附加到 PID 并报告

w ... 文件已打开以供写入。

简单的 bash 脚本

#!/usr/local/bin/bash
my_file=/scratch/test-file
result=`fuser $my_file 2>&1`
pid=`echo $result | cut -d ':' -f 2-`
if [ -z "$pid" ]; then
    echo "$my_file is not opened by any process"
else
    echo "$my_file is opened by process PID(s): $pid"
fi

节目

# ./test.bash
/scratch/test-file is opened by process PID(s): 45448w 45042

分别

# ./test.bash
/scratch/test-file is not opened by any process

如果这对您不起作用,请参阅如何创建最小、完整和可验证的示例以提供详细信息。

于 2019-02-19T05:58:20.163 回答
1

我的结论fuser是在 FreeBSD 中被破坏了。最后,我解析了fstat输出来解决问题。 fstat在正在积极写入的文件上产生以下输出(并且还有另一个进程正在读取它,因此有两行):

# fstat file 
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W NAME
root     smbd       36299   41 /data    1282756 -rwxr--r--  7407140864 rw  file
root     smbd       36295   30 /data    1282756 -rwxr--r--  7407140864  r  file

以下 bash 代码使用 测试文件fstat,删除标题行 ( sed),然后使用awk抓取第 9 列,即文件是否打开以供读取或写入。然后A在任何行中grep查找w写入标志。如果它找到一个,它将返回 true。整个条件被否定 ( !) 以确保仅在文件未使用时才执行操作:

 if [[ ! `/usr/bin/fstat "$FILE" | sed 1d | awk '{print $9}' | grep "w"` ]]
 then
    ... do something ...
 fi
于 2019-02-21T21:56:04.250 回答
0

如果fuser在您的系统中不起作用并且可以进行一些解析,请尝试一下fstat,例如,在打开文件时:

$ cat > /tmp/test

这是的输出 fstat /tmp/test

# fstat /tmp/text
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W NAME
root     cat        39590    1 [restricted]   3812 -rw-r--r--       0  w  /tmp/text

如果该文件未在使用中,您将只获得标题:

# fstat /tmp/text
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W NAME

那么你可以使用类似的东西:

[ `fstat /tmp/test | wc -l` -gt 1 ] && echo "in use"

或者

test `fstat /tmp/test | wc -l` -gt 1 && echo "in use"
于 2019-02-19T17:29:46.547 回答
0

您所描述的“损坏”也可能是正确的行为,具体取决于进程所有者权限。

您只能通过 看到自己的进程fuser,除非您具有 root 或同等权限并且可以看到其他用户的进程。确保您以相同的 / root 用户身份运行两个会话。

于 2019-02-28T16:58:17.073 回答