echo 输出的内容中包括调用的变量时为何会自动乱序?内详

2023-02-28 01:52:16 +08:00
 mylovesaber

本意是希望下载 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-LimitX-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

有没有大佬知道这是什么原因导致的顺序错乱?是我疏忽了什么地方吗?

2219 次点击
所在节点    Linux
36 条回复
mylovesaber
2023-02-28 03:34:57 +08:00
解决了,估计 github 写 api 那老哥电脑是 windows 的,导致返回的 header 信息每一行都带上了 win 特有的结尾符号,在变量 githubGetRateInfo 后面加上: `|tr -d '\r'` 即可
geelaw
2023-02-28 04:36:53 +08:00
@mylovesaber #1 不太确定您的结论是如何来的,但是据我所知使用 CR LF 标记大多数行结尾是 HTTP 规定的,而且是自古以来。
julyclyde
2023-02-28 08:52:58 +08:00
@geelaw HTTP 里用 crlf ,和 curl 输出 crlf 是两码事
AoEiuV020CN
2023-02-28 09:10:31 +08:00
这么调岂不是又多浪费了一次,header 还不好解析,
github 有提供专用的接口获取 api 限制以及剩下的次数,json 直接 jq 还方便解析,

https://api.github.com/rate_limit
aloxaf
2023-02-28 09:15:13 +08:00
无法复现,你的环境及 curl 版本是多少?
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'
```
hahahahahahahah
2023-02-28 11:43:36 +08:00
你是直接在命令行执行的还是写到 sh 里面执行的
geelaw
2023-02-28 11:47:57 +08:00
@julyclyde #3 curl 不参与编码解析,自然是 HTTP 给什么就返回什么,否则(若是 curl 参与编码解析的话)你把 curl 传入管道的时候会出现非常糟糕的状况。
julyclyde
2023-02-28 13:11:20 +08:00
@geelaw 并不是的。http 一直都 crlf ,但是 linux 版本的 curl 的输出是\n 而不是\r\n
ysc3839
2023-02-28 13:26:09 +08:00
@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|
julyclyde
2023-02-28 14:23:39 +08:00
@ysc3839 居然真的是 0d0a ;换了 github 之外的网址也是 0d0a
我服了

这样的话,OP 的假设就被推翻了呢,并不是“因为 github 的人用 windows”而导致 crlf ,而是 shell 没能正确处理 crlf ?
geelaw
2023-02-28 14:30:24 +08:00
@julyclyde #11 是你对 shell 的期待有误,Unix 风格 shell 的管道完全是二进制的,任何对数据的解读都是程序完成。

Re: “OP 的假设就被推翻了呢”
为什么你会觉得 OP 的假设是自然的?那明明是《我比 GitHub 做 Web API 的员工更懂 HTTP 之口嗨 Windows 用户真时髦》最新一期。
aloxaf
2023-02-28 14:32:38 +08:00
@aloxaf #5 啊,我搞错了,确实可以复现

原先都没注意过这个问题,也用 shell 处理过几次 curl 输出,竟然一直没踩坑
julyclyde
2023-02-28 15:12:24 +08:00
@geelaw curl 既然“按文本”输出,按说应该遵照 unix 风格的习惯用\n 啊。这是我的想法。
看起来它并没有把每一行要输出的内容“按文本”输出,而是把从 HTTP 读到的直接发给 stdout 了
geelaw
2023-02-28 15:32:09 +08:00
@julyclyde #14 然而你的这个想法和 #3 体现的想法是矛盾的,如果你认为 curl 应该“按文本”输出,那也和 GitHub Web API 输出的是 CRLF 还是 LF 没有关系,因为此时你认为的 curl 的行为会让用户无法感知 HTTP 传输的到底是 CRLF 还是 LF 。
julyclyde
2023-02-28 15:44:37 +08:00
@geelaw 我确实认为和 github 输出的是“哪一种换行”没什么关系啊。
http 用 crlf 是遵循标准
curl 输出 crlf 在我看来简直是无法想象的事情。虽然 OP 自己说是 crlf 了,但我当时是不信的。我并没有按你推测的那么认为
flyqie
2023-02-28 15:54:15 +08:00
@julyclyde #16

curl 要是输出的不标准你信不信会被一堆人围着骂。。

curl 可以跨平台,它必须尽力保证在各平台之间的统一性。

况且,curl 从来就不是"按文本"输出,它只是原样返回数据,你觉得它按文本输出只是因为这玩意它就是文本。。

我倒是认为 curl 就是应该返回 crlf ,这是协议指定的,curl 做的就应该是把请求原样返回到 stdout ,这没有任何疑问。
mylovesaber
2023-02-28 17:40:06 +08:00
@geelaw 那肯定是我理解问题了,我不太了解这东西有说错的还请见谅
mylovesaber
2023-02-28 17:43:11 +08:00
@AoEiuV020CN 我是从这看到的:
https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#rate-limiting

json 的话我为了解析还得再拉一个 jq ,而现在环境写这个解析判定就是为了拉一个 yq ,反而有种鸡和蛋谁先出现的辩论感觉了,不过还是感谢,我之前不知道这方式
mylovesaber
2023-02-28 17:45:23 +08:00
@AoEiuV020CN 我刚刚反复网页刷新你发的这个链接,能看到剩余次数也在随着刷新的变化而变化,但几个小时不登录的话,居然可用只剩余 20 次,有点意外。。。另外对于下载 release 中文件的操作,具体指的是接口中的哪个 key 呢?下载地址: https://api.github.com/repos/mikefarah/yq/releases/latest

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/919678

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX