【问题标题】:How to get remote file size from a shell script?如何从 shell 脚本获取远程文件大小?
【发布时间】:2011-05-28 17:16:19
【问题描述】:

有没有办法获取远程文件的大小,例如

http://api.twitter.com/1/statuses/public_timeline.json

在 shell 脚本中?

【问题讨论】:

  • 这个页面的例子很少,这里是一个用于 Windows shell 脚本的例子(可以兼作 bash 脚本,只需稍加修改)superuser.com/a/1007898/429721
  • wget --spider 怎么样?

标签: shell filesize


【解决方案1】:

您可以下载文件并获取其大小。但我们可以做得更好。

使用curl 仅使用-I 选项获取response header

在响应头中查找Content-Length:,后面是文件的大小(以字节为单位)。

$ URL="http://api.twitter.com/1/statuses/public_timeline.json"
$ curl -sI $URL | grep -i Content-Length
Content-Length: 134

要获取大小,请使用过滤器从上面的输出中提取数字部分:

$ curl -sI $URL | grep -i Content-Length | awk '{print $2}'
134

【讨论】:

  • 使用了这个函数,想把结果发送给一个函数来格式化字节为 KB 或 MB,它有一个隐藏的回车,将结果通过管道传送到 tr -d '\r' 删除它们。
  • curl -sI $URL | grep -i content-length 为避免区分大小写,您必须在 grep 中使用 -i
  • 不适合我curl -sI https://code.jquery.com/jquery-3.1.1.min.js | grep -i content-length
  • 使用 cut -d' ' -f2 代替 awk。 awk 比 cut 更大更慢。需要明确的是,这是单引号之间的空格。否则,这个答案对我有用。
【解决方案2】:

类似于codaddict's answer,但没有调用grep

curl -sI http://api.twitter.com/1/statuses/public_timeline.json | awk '/Content-Length/ { print $2 }'

【讨论】:

  • 具有讽刺意味的是,您选择的示例 URL 使用小写标题字符串 content-length,这会破坏您的命令。在 awk 中有很多方法可以忽略大小写,但这是最安全的:curl -sI http://api.twitter.com/1/statuses/public_timeline.json | awk '/[Cc]ontent-[Ll]ength/ { print $2 }' ...当然 grep 也不错 ;)
  • 我猜标题在我的回答和此评论之间的四年内发生了变化:)
【解决方案3】:

对其他答案的两个警告:

  1. 某些服务器不会为 HEAD 请求返回正确的 Content-Length,因此您可能需要进行完整下载。
  2. 除非您指定 gzip/deflate 标头,否则您可能会收到不切实际的大响应(与现代浏览器相比)。

此外,您可以在没有 grep/awk 或管道的情况下执行此操作:

curl 'http://api.twitter.com/1/statuses/public_timeline.json' --location --silent --write-out 'size_download=%{size_download}\n' --output /dev/null

还有同样的压缩请求:

curl 'http://api.twitter.com/1/statuses/public_timeline.json' --location --silent  -H 'Accept-Encoding: gzip,deflate' --write-out 'size_download=%{size_download}\n' --output /dev/null

【讨论】:

  • 这似乎不适用于重定向。这不也下载整个文件吗?
  • @TomHale 我想你可以在命令中添加-L 来跟踪重定向(我没有方便的重定向 URL 来测试)。而且,是的,它会下载整个文件。
  • 如果您可以依靠您查询的 Web 服务器为 HEAD 请求返回准确的 Content-Length,则无需下载整个文件。只需在上面的示例中添加 -I 即可查看它如何返回零(至少在 2019 年 2 月 25 日是这样)。我的解决方案更通用。
【解决方案4】:

当有重定向时,前面的答案将不起作用。例如,如果想要 debian iso DVD 的大小,他必须使用 --location 选项,否则,报告的大小可能是 302 Moved Temporarily 答案正文的大小,而不是真实文件的大小。
假设您有以下网址:

$ url=http://cdimage.debian.org/debian-cd/8.1.0/amd64/iso-dvd/debian-8.1.0-amd64-DVD-1.iso

使用 curl,您可以获得:

$ curl --head --location ${url}
HTTP/1.0 302 Moved Temporarily
...
Content-Type: text/html; charset=iso-8859-1
...

HTTP/1.0 200 OK
...
Content-Length: 3994091520
...
Content-Type: application/x-iso9660-image
...

这就是我更喜欢使用HEAD 的原因,它是libwww-perl 包(在debian 上)中lwp-request 命令的别名。它的另一个优点是它去除了额外的 \r 字符,从而简化了后续的字符串处理。

因此,要检索 debian iso DVD 的大小,可以这样做:

$ size=$(HEAD ${url})
$ size=${size##*Content-Length: }
$ size=${size%%[[:space:]]*}

请注意:

  • 此方法只需要启动一个进程
  • 它只适用于 bash,因为使用了特殊的扩展语法

对于其他 shell,您可能不得不求助于 sed、awk、grep 等。

【讨论】:

  • 不错的答案。是否有可能在单行中做到这一点?
  • size=$(HEAD ${url} | grep "Content-Length:" | sed 's/.*: //')
  • 对不起,我不知道如何编辑我之前发布的太快的评论。我刚刚发布的单线解决方案将起作用,但代价是创建 2 个额外的进程。另一方面,它应该兼容更多的shell。
【解决方案5】:

将以上所有内容结合起来为我工作:

URL="http://cdimage.debian.org/debian-cd/current/i386/iso-dvd/debian-9.5.0-i386-DVD-1.iso"
curl --head --silent --location "$URL" | grep -i "content-length:" | tr -d " \t" | cut -d ':' -f 2

这将只返回以字节为单位的内容长度:

3767500800

【讨论】:

    【解决方案6】:

    不同的解决方案:

    ssh userName@IP ls -s PATH | grep FILENAME | awk '{print$1}'
    

    以 KB 为单位提供大小

    【讨论】:

    • 只有当我们在托管 url 内容的同一台服务器上有一个 ssh 帐户时才有效,这是一个非常强的约束。
    【解决方案7】:

    接受的解决方案对我不起作用,这是:

    curl -s https://code.jquery.com/jquery-3.1.1.min.js | wc -c
    

    【讨论】:

    • @fguillen 你不认为从标题中获取数据更好吗?因为这实际上会将文件缓冲区下载到wc
    • @0x616f 你是对的,这个信息也在标题中。你能提出一个解决方案并通知我吗?我会投票赞成的;)
    【解决方案8】:

    我像这样使用([Cc]ontent-[Ll]ength:),因为我让服务器在标题响应中给出了多个 Content-Length 字符

    curl -sI "http://someserver.com/hls/125454.ts" | grep [Cc]ontent-[Ll]ength: | awk '{ print $2 }'
    

    Accept-Ranges: bytes Access-Control-Expose-Headers: Date, Server, Content-Type, Content-Length Server: WowzaStreamingEngine/4.5.0 Cache-Control: no-cache Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: OPTIONS, GET, POST, HEAD Access-Control-Allow-Headers: Content-Type, User-Agent, If-Modified-Since, Cache-Control, Range Date: Tue, 10 Jan 2017 01:56:08 GMT Content-Type: video/MP2T Content-Length: 666460

    【讨论】:

      【解决方案9】:

      我认为最简单的方法是:

      1. 使用 cURL 以静默模式运行 -s

      2. 只拉出标题-I(以免下载整个文件)

      3. 然后执行不区分大小写的 grep -i

      4. 并使用 awk $2 返回第二个参数。

      5. 输出返回为bytes

      示例:

      curl -sI http://api.twitter.com/1/statuses/public_timeline.json | grep -i content-length | awk '{print $2}'
      
      //output: 52
      

      curl -sI https://code.jquery.com/jquery-3.1.1.min.js | grep -i content-length | awk '{print $2}'
      
      //output: 86709
      

      curl -sI http://download.thinkbroadband.com/1GB.zip | grep -i content-length | awk '{print $2}'
      
      //output: 1073741824
      

      显示为千字节/兆字节

      如果您想以千字节为单位显示大小,请将 awk 更改为:

      awk '{print $2/1024}'
      

      或兆字节

      awk '{print $2/1024/1024}'
      

      【讨论】:

        【解决方案10】:

        这将显示有关正在进行的下载的详细信息

        你只需要像下面的例子一样指定一个 URL。

        $ curl -O -w 'We downloaded %{size_download} bytes\n' 
        https://cmake.org/files/v3.8/cmake-3.8.2.tar.gz
        

        输出

          % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                         Dload  Upload   Total   Spent    Left  Speed
        100 7328k  100 7328k    0     0   244k      0  0:00:29  0:00:29 --:--:--  365k
        We downloaded 7504706 bytes
        

        出于自动化目的,您只需将命令添加到您的 脚本文件。

        【讨论】:

          【解决方案11】:

          我有一个基于 codaddict's answer 的 shell 函数,它以人类可读的格式提供远程文件的大小:

          remote_file_size () {
            printf "%q" "$*"           |
              xargs curl -sI           |
              grep Content-Length      |
              awk '{print $2}'         |
              tr -d '\040\011\012\015' |
              gnumfmt --to=iec-i --suffix=B # the `g' prefix on `numfmt' is only for systems
            # ^                             # that lack the GNU coreutils by default, i.e.,
            # |                             # non-Linux systems
            # |
            # |                             # in other words, if you're on Linux, remove this
            # |                             # letter `g'; if you're on BSD or Mac, install the GNU coreutils
          } # |                                        |
            # +----------------------------------------+
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-09-12
            • 2023-03-04
            • 2019-04-27
            • 2011-10-13
            • 1970-01-01
            • 1970-01-01
            • 2015-03-05
            • 1970-01-01
            相关资源
            最近更新 更多