AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 415596
Accepted
Jake Wilson
Jake Wilson
Asked: 2012-08-09 08:03:46 +0800 CST2012-08-09 08:03:46 +0800 CST 2012-08-09 08:03:46 +0800 CST

确定文件是否正在被写入?

  • 772

我需要部署一个自动化进程(通过 1 分钟的 cron 脚本)来查找特定目录中的 tar 文件。如果找到 tar 文件,则会将其解压缩到适当的位置,然后删除 tar 文件。

tar 文件通过 SSH 从另一台服务器自动复制到该服务器。在某些情况下,tar 文件非常大,包含很多文件。

我预计会遇到的问题:如果将 tar 文件复制到服务器需要 > 1 分钟,并且 cron 脚本每分钟运行一次,它将看到 .tar.gz 文件并尝试执行解压它,即使 tar 文件仍在写入过程中。

有什么方法(通过 bash 命令)来测试当前是否正在写入文件,或者它是否只是部分文件等?

我想到的一种替代方法是将文件复制为不同的文件扩展名(如.tar.gz.part),然后.tar.gz在传输完成后重命名为。但是我想我会尝试弄清楚是否有一种方法可以首先在命令行确定文件是否完整......有什么线索吗?

linux
  • 7 7 个回答
  • 68050 Views

7 个回答

  • Voted
  1. MikeyB
    2012-08-09T08:09:46+08:002012-08-09T08:09:46+08:00

    最好的办法是使用lsof确定文件是否已被任何进程打开:

    #  lsof -f -- /var/log/syslog
    COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
    rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog
    

    您无法轻易判断它是否正在被写入,但如果正在被写入,则它必须是打开的。


    编辑:让我们在这里解决实际问题,而不是尝试实施建议的解决方案!

    使用 rsync 传输文件:

    ○ → rsync -e ssh remote:big.tar.gz .
    

    这样,文件不会复制到现有文件之上,而是复制到临时文件 ( .big.tar.gz.XXXXXX) 中,直到传输完成,然后移动到位。

    • 16
  2. Best Answer
    Alex
    2012-08-09T08:08:41+08:002012-08-09T08:08:41+08:00

    你在正确的轨道上,重命名文件是一个原子操作,所以上传后执行重命名简单、优雅且不易出错。我能想到的另一种方法是使用lsof | grep filename.tar.gz检查文件是否正在被另一个进程访问。

    • 14
  3. Andrew Henle
    2018-04-21T10:31:38+08:002018-04-21T10:31:38+08:00

    有点旧,但大多数答案完全没有抓住问题的要点:

    但我想我会尝试弄清楚是否有一种方法可以首先在命令行确定文件是否完整......

    一般来说,没有。您根本没有足够的信息来确定这一点。

    因为确定文件已关闭与确定文件是否完整不同。例如,如果连接在传输中途丢失,文件将“关闭”。

    只有@Alex 的回答是正确的。甚至他也因为使用lsof了一些东西而倒下了。

    要确定文件是否已完全、成功传输,需要更多数据。如:

    我想到的一种替代方法是将文件复制为不同的文件扩展名(如.tar.gz.part),然后.tar.gz在传输完成后重命名为。

    这是传达文件已完全成功传输的完美方式。你也可以将文件从一个目录移动到另一个目录,只要你在同一个文件系统中。或者让发件人发送一个空filename.done文件来表示完成。

    但是所有方法都必须依赖于发送方以某种方式发出传输已成功完成的信号。因为只有发件人拥有该信息。

    某些文件格式(如 PDF)中包含数据,可让您确定文件是否完整。但是您必须打开并阅读几乎整个文件才能找到答案。

    lsof只会告诉您该文件不再打开 - 它不会告诉您为什么它不再打开。它也不会告诉您文件应该有多大。

    • 7
  4. Kyle
    2012-08-09T08:36:02+08:002012-08-09T08:36:02+08:00

    最好的方法是使用incron(“inotify cron 系统”)。它允许您在目录上设置一个inotify监视,然后通知您文件操作。在这种情况下,您应该查看目录以查找 close_write。一旦文件在写入后关闭,这将允许您运行命令。

    • 5
  5. Kevin Baragona
    2015-07-26T18:57:08+08:002015-07-26T18:57:08+08:00

    似乎 lsof 可以检测文件在什么模式下打开:

    lsof -f -- a_file
    COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
    cat     52391 bob    1w   REG    1,2       15 19545007 a_file
    

    看到上面写着 1w 的地方了吗?这意味着文件描述符编号为 1,模式为 w,即写入。

    • 2
  6. teeedubb
    2019-11-15T19:47:24+08:002019-11-15T19:47:24+08:00

    使用inotifywait可以实现你所追求的——它有能力在执行命令之前等到文件写入完成。

    以下将持续监视文件夹中的新文件,并在写入文件完成后循环执行命令。

    WATCH_DIR=/directory/to/monitor
    DEST_DIR=/x/y/z
    
    /usr/bin/inotifywait --recursive --monitor --quiet -e moved_to -e close_write --format '%w%f' "$WATCH_DIR" | while read -r INPUT_FILE; do
    
    mv "$0" "$DEST_DIR"
    
    done
    

    有关更多配置选项,请参阅https://linux.die.net/man/1/inotifywatch

    • 1
  7. Cristian Barreto
    2020-04-19T06:38:16+08:002020-04-19T06:38:16+08:00

    我使用一个 python 脚本来迭代大小检查,直到它在不同时间的 2 次迭代中相同(在我的例子中,检查之间有 0.05 秒的差异,工作完成了!):

        dict={}
        for filename in os.listdir(basepath+'/in'+stage):
    
            fullInFilename=myfile
    
            try:
                if not filename in dict:
                    #nuevo item...
                    time.sleep(0.05)
                    dict = {filename: os.stat(fullInFilename).st_size}
                    break
                else:  # ya existe en dict, terminó de copiar?
                    time.sleep(0.05)
                    sizeRegistrado = dict[filename]
                    sizeActual = os.stat(fullInFilename).st_size
    
                    if sizeActual != sizeRegistrado:
                        # sigue copiando...
                        dict[filename] = sizeActual
                        print(sizeActual)
                        break
                    else:
                        # Terminada
                        #print("pop!")
                        dict.pop(filename)
    
    • 0

相关问题

  • Linux 主机到主机迁移

  • 如何在 Linux 机器上找到有关硬件的详细信息?

  • 如何在 Linux 下监控每个进程的网络 I/O 使用情况?

  • 在 RHEL4 上修改 CUPS 中的现有打印机设置

  • 为本地网络中的名称解析添加自定义 dns 条目

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve