本意是希望下载 github 文件的时候先检查下有没有达到拉取频率上限,并打印出提示信息,但输出的提示信息是乱序的,具体命令如下一行一条命令:
githubGetRateInfo=$(curl -s -I -X POST https://api.github.com/users/octocat)
postLimit=$(echo "${githubGetRateInfo}"|awk /^X-RateLimit-Limit/'{print $2}')
postRemaining=$(echo "${githubGetRateInfo}"|awk /^X-RateLimit-Remaining/'{print $2}')
echo "GitHub 调用速率为 ${postLimit} 次 /小时"
echo 输出结果预期效果:
GitHub 调用速率为 60 次 /小时
实际输出:
次 /小时 用速率为 60
以下是 curl 那条命令获取的信息,目的是筛选出X-RateLimit-Limit
和X-RateLimit-Remaining
的值
HTTP/1.1 404 Not Found
Server: GitHub.com
Date: Mon, 27 Feb 2023 17:37:26 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 84
X-GitHub-Media-Type: github.v3; format=json
x-github-api-version-selected: 2022-11-28
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1677522152
X-RateLimit-Used: 3
X-RateLimit-Resource: core
Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Content-Security-Policy: default-src 'none'
Vary: Accept-Encoding, Accept, X-Requested-With
X-GitHub-Request-Id: xxxxxxxxxxx
有没有大佬知道这是什么原因导致的顺序错乱?是我疏忽了什么地方吗?
1
mylovesaber OP 解决了,估计 github 写 api 那老哥电脑是 windows 的,导致返回的 header 信息每一行都带上了 win 特有的结尾符号,在变量 githubGetRateInfo 后面加上: `|tr -d '\r'` 即可
|
2
geelaw 2023-02-28 04:36:53 +08:00 6
@mylovesaber #1 不太确定您的结论是如何来的,但是据我所知使用 CR LF 标记大多数行结尾是 HTTP 规定的,而且是自古以来。
|
4
AoEiuV020CN 2023-02-28 09:10:31 +08:00 via Android
这么调岂不是又多浪费了一次,header 还不好解析,
github 有提供专用的接口获取 api 限制以及剩下的次数,json 直接 jq 还方便解析, https://api.github.com/rate_limit |
5
aloxaf 2023-02-28 09:15:13 +08:00
无法复现,你的环境及 curl 版本是多少?
|
6
HappyStraw 2023-02-28 10:03:41 +08:00
https://www.rfc-editor.org/rfc/rfc2616#section-5
```text Request = Request-Line ; Section 5.1 *(( general-header ; Section 4.5 | request-header ; Section 5.3 | entity-header ) CRLF) ; Section 7.1 CRLF [ message-body ] ``` 1. HTTP 是 CRLF 换行, 不是用不用 windows 的问题. 2. 在 Archlinux curl 7.88.1 下, HEAD https://api.github.com/users/octocat, 返回为 http/2, header 为小写 ```text HTTP/2 404 server: GitHub.com date: Tue, 28 Feb 2023 01:45:47 GMT content-type: application/json; charset=utf-8 content-length: 84 x-github-media-type: github.v3; format=json x-github-api-version-selected: 2022-11-28 x-ratelimit-limit: 60 x-ratelimit-remaining: 52 x-ratelimit-reset: 1677550667 x-ratelimit-used: 8 x-ratelimit-resource: core ...省略 ``` 3. awk 设置 IGNORECASE=1 大小写不敏感, 如: ```bash echo "${githubGetRateInfo}"|awk 'BEGIN{IGNORECASE=1}/^X-RateLimit-Limit:/{print $2}'|tr -d '\r' ``` |
7
hahahahahahahah 2023-02-28 11:43:36 +08:00 via iPhone
你是直接在命令行执行的还是写到 sh 里面执行的
|
8
geelaw 2023-02-28 11:47:57 +08:00
@julyclyde #3 curl 不参与编码解析,自然是 HTTP 给什么就返回什么,否则(若是 curl 参与编码解析的话)你把 curl 传入管道的时候会出现非常糟糕的状况。
|
10
ysc3839 2023-02-28 13:26:09 +08:00 via Android
@julyclyde 可以自己试试,我这里输出的就是 CRLF
$ curl -s -I -X POST https://api.github.com/users/octocat | hexdump -C 00000000 48 54 54 50 2f 32 20 34 30 34 20 0d 0a 73 65 72 |HTTP/2 404 ..ser| |
11
julyclyde 2023-02-28 14:23:39 +08:00
@ysc3839 居然真的是 0d0a ;换了 github 之外的网址也是 0d0a
我服了 这样的话,OP 的假设就被推翻了呢,并不是“因为 github 的人用 windows”而导致 crlf ,而是 shell 没能正确处理 crlf ? |
12
geelaw 2023-02-28 14:30:24 +08:00
@julyclyde #11 是你对 shell 的期待有误,Unix 风格 shell 的管道完全是二进制的,任何对数据的解读都是程序完成。
Re: “OP 的假设就被推翻了呢” 为什么你会觉得 OP 的假设是自然的?那明明是《我比 GitHub 做 Web API 的员工更懂 HTTP 之口嗨 Windows 用户真时髦》最新一期。 |
13
aloxaf 2023-02-28 14:32:38 +08:00
|
14
julyclyde 2023-02-28 15:12:24 +08:00
@geelaw curl 既然“按文本”输出,按说应该遵照 unix 风格的习惯用\n 啊。这是我的想法。
看起来它并没有把每一行要输出的内容“按文本”输出,而是把从 HTTP 读到的直接发给 stdout 了 |
15
geelaw 2023-02-28 15:32:09 +08:00
@julyclyde #14 然而你的这个想法和 #3 体现的想法是矛盾的,如果你认为 curl 应该“按文本”输出,那也和 GitHub Web API 输出的是 CRLF 还是 LF 没有关系,因为此时你认为的 curl 的行为会让用户无法感知 HTTP 传输的到底是 CRLF 还是 LF 。
|
16
julyclyde 2023-02-28 15:44:37 +08:00
@geelaw 我确实认为和 github 输出的是“哪一种换行”没什么关系啊。
http 用 crlf 是遵循标准 curl 输出 crlf 在我看来简直是无法想象的事情。虽然 OP 自己说是 crlf 了,但我当时是不信的。我并没有按你推测的那么认为 |
17
flyqie 2023-02-28 15:54:15 +08:00 via Android
@julyclyde #16
curl 要是输出的不标准你信不信会被一堆人围着骂。。 curl 可以跨平台,它必须尽力保证在各平台之间的统一性。 况且,curl 从来就不是"按文本"输出,它只是原样返回数据,你觉得它按文本输出只是因为这玩意它就是文本。。 我倒是认为 curl 就是应该返回 crlf ,这是协议指定的,curl 做的就应该是把请求原样返回到 stdout ,这没有任何疑问。 |
18
mylovesaber OP @geelaw 那肯定是我理解问题了,我不太了解这东西有说错的还请见谅
|
19
mylovesaber OP @AoEiuV020CN 我是从这看到的:
https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#rate-limiting json 的话我为了解析还得再拉一个 jq ,而现在环境写这个解析判定就是为了拉一个 yq ,反而有种鸡和蛋谁先出现的辩论感觉了,不过还是感谢,我之前不知道这方式 |
20
mylovesaber OP @AoEiuV020CN 我刚刚反复网页刷新你发的这个链接,能看到剩余次数也在随着刷新的变化而变化,但几个小时不登录的话,居然可用只剩余 20 次,有点意外。。。另外对于下载 release 中文件的操作,具体指的是接口中的哪个 key 呢?下载地址: https://api.github.com/repos/mikefarah/yq/releases/latest
|
21
mylovesaber OP @aloxaf 7.81.0 和 7.29.0 都存在,前者服务器 ubuntu minimal22.04 ,后者应该是 centos7 ,
|
22
mylovesaber OP @hahahahahahahah 两个方式都尝试了,最开始脚本中出现意外输出,手动 echo 也出现了
|
23
mylovesaber OP @geelaw 是我理解的太无脑让大家见笑了,之前的确没遇到过这问题,第一次遇到给整懵了,网上查也没头绪,没想到是编码的问题
|
24
mylovesaber OP @julyclyde 哈哈,其实你也理解错我意思了,我是有点调侃甩锅的意思,但我基于假设 curl 远端显示什么就应该原封不动得打印给我的默认想法的,而不是让 curl 对输出的结果做解析后再反馈给我
|
25
mylovesaber OP 关于本贴问题我昨天加班到凌晨刚准备走,最后一次测试居然发现有这个问题就两头都发了请教,那边给到了我提示,然后我把我的处理方法也补充进去了,v2 没法在回复中用 md ,也没法编辑超时的帖子,所以直接贴隔壁站的链接吧。
https://stackoverflow.com/questions/75584213/if-the-text-output-by-linux-echo-contains-variables-the-text-will-be-out-of-ord |
26
AoEiuV020CN 2023-02-28 18:06:58 +08:00
@mylovesaber #20 这个接口不会占用次数的,变了说明有其他人在用你一样的 ip ,你没有唯一的公网 ip 吧,
建议带上 token 再调用 api ,就和 ip 无关了, 下载地址的话就是 browser_download_url , 诶你既然要解析下载地址,那不还是要提前拉一个 jq 或者其他什么解析 json 的,rate limit 不就可以一样的办法解析处理, 还是没必要读 header 呀, 官方 header 用途是你实际调用后判断是否还有剩次数,而不是在实际使用之前特地去拿 header 的, |
27
mylovesaber OP @AoEiuV020CN 我是为了应对不同数据库的备份要求,写了个 shell 的工具,然后读取配置文件来实现获取信息,读的是 yml ,所以解析工具就需要拉一个 yq ,还对应加了一个可以检测 yq 是否有升级的模块,然后测试下载、校验等操作的代码是否工作正常的时候意外遇到了 github 有解析上限的问题,所以不得以才加了个 25 楼的模块用于检查上限的问题,再为了不占用次数的话引入个 jq 感觉是不是有点多此一举哈哈,我想了解的 key 不是那个,是你发的那个链接里面有五段,每段都有各自的 rate limit 和 remaining 信息,我不知道如果是获取 release 文件链接的话应该会占用哪个 rate limit 和 remaining 信息
--- 获取下载链接的话这两行就够了: ```shell remoteYQLatestHTML="$(curl -s --max-time 15 v 站不能用外链 repos/mikefarah/yq/releases/latest)" yqDownloadLink=$(echo "${remoteYQLatestHTML}" | grep "browser_download_url.*.yq_linux_amd64\"" | awk -F '[" ]' '{print $(NF-1)}') ``` |
28
AoEiuV020CN 2023-02-28 18:58:46 +08:00 via Android
|
29
AoEiuV020CN 2023-02-28 19:03:13 +08:00 via Android
@mylovesaber #27 顺便我也遇到过同样问题,
我最后是选择打印 http code ,api 失败就报错不继续, 顺便加上了 token ,有 token 一小时免费一千次,没有 token 一个 ip 一小时免费只有 60 次,太小气了, |
30
AoEiuV020CN 2023-02-28 19:06:39 +08:00 via Android
|
31
AoEiuV020CN 2023-02-28 19:07:16 +08:00 via Android
|
32
mylovesaber OP @AoEiuV020CN 这样 ok 了,还是不减次数的舒服啊,直接筛选出来就是数字,根本不用 string 转 int
githubGetRateInfo=$(curl -s https://api.github.com/rate_limit|xargs|grep -o "rate: {.*.}"|sed 's/,/\n/g; s/{/\n/g; s/}/\n/g; s/ \+//g') postLimit=$(echo "${githubGetRateInfo}" | awk -F ':' /^limit/'{print $2}') postRemaining=$(echo "${githubGetRateInfo}" | awk -F ':' /^remaining/'{print $2}') |
33
mylovesaber OP @AoEiuV020CN 公司都是搭建的 gitlab ,不用 github ,所以我自己调用问题不大,不过还是感谢分享,否则之前用的那个调一次少一次
|
34
julyclyde 2023-03-01 11:26:25 +08:00
echo -n ${postLimit}|hexdump -C
00000000 36 30 0d |60.| 可以看出来 postLimit 变量里面最后含有一个 0d 所以,为什么 echo "GitHub 调用速率为 ${postLimit} 次 /小时" 的结果是 次 /小时用速率为 60 呢? echo "GitHub 调用速率为 ${postLimit} 次 /小时" |hexdump -C 00000000 47 69 74 48 75 62 20 e8 b0 83 e7 94 a8 e9 80 9f |GitHub .........| 00000010 e7 8e 87 e4 b8 ba 20 36 30 0d 20 e6 ac a1 20 2f |...... 60. ... /| 00000020 e5 b0 8f e6 97 b6 0a |.......| 00000027 看起来输出内容是对的,但是显示效果有问题 |