全球主机交流论坛

标题: 为了同步时间,我绞尽脑汁写了个bash脚本,很粗糙, [打印本页]

作者: yaoruisheng    时间: 2024-3-6 08:07
标题: 为了同步时间,我绞尽脑汁写了个bash脚本,很粗糙,
盒子一断电就丢失时间,每次都要设置。。。
查了不少资料,才写下这么段脚本。

我土木工程专业的,非专业勿喷。

  1. #!/usr/bin/bash
  2. #
  3. exec 5<>/dev/udp/ntp.tencent.com/123
  4. echo -e -n "\\x1b\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"  >&5

  5. resp=$(timeout 2 dd bs=48 count=1 <&5 2>/dev/null | sed -n "s/.\{40\}\(.\{4\}\)/\1/p")

  6. printf -v r1 "%02x" "'${resp:0:1}"
  7. printf -v r2 "%02x" "'${resp:1:1}"
  8. printf -v r3 "%02x" "'${resp:2:1}"
  9. printf -v r4 "%02x" "'${resp:3:1}"
  10. r=${r1}${r2}${r3}${r4}

  11. d=`expr $((0x${r})) - 2208988800`

  12. date -s "@$d"
复制代码

作者: 谷歌云    时间: 2024-3-6 08:12
干嘛不用 GPT
作者: icon    时间: 2024-3-6 08:14
ntpdate不直接就可以了么? 为什么要这么大段?
作者: yaoruisheng    时间: 2024-3-6 08:15
icon 发表于 2024-3-6 08:14
ntpdate不直接就可以了么? 为什么要这么大段?

盒子空间有限,ntpdate 安装容量太大
作者: yaoruisheng    时间: 2024-3-6 08:17
icon 发表于 2024-3-6 08:14
ntpdate不直接就可以了么? 为什么要这么大段?

本来打算纯shell语言写,发现没办法实现。

需要额外的dd sed和expr命令。
作者: hcyme    时间: 2024-3-6 08:19
盒子同步确实麻烦,而且各家地址不同
作者: Sam_Edward    时间: 2024-3-6 08:27
没玩过盒子,不明白为什么要同步,另外以下是chatgpt 优化过的代码,你自己看对不对,不知道你要用于做什么:

  1. #!/usr/bin/bash

  2. # NTP服务器地址和端口
  3. NTP_SERVER="ntp.tencent.com"
  4. NTP_PORT=123

  5. # 创建UDP连接
  6. exec 5<>/dev/udp/${NTP_SERVER}/${NTP_PORT}

  7. # 发送NTP请求包 (NTP协议指定的格式)
  8. printf '\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' >&5

  9. # 读取并处理NTP响应
  10. if read -u 5 -t 2 -r -n 48 response; then
  11.   # 提取时间戳并转换为十进制
  12.   time_stamp=$(printf '%d\n' "'${response:43:1}'")
  13.   for ((i=1; i<4; i++)); do
  14.     printf -v temp '%d' "'${response:43+i:1}'"
  15.     time_stamp=$((time_stamp*256 + temp))
  16.   done

  17.   # 转换NTP时间戳到Unix时间戳
  18.   unix_time=$((time_stamp - 2208988800))

  19.   # 设置系统时间
  20.   if date -s "@$unix_time" > /dev/null; then
  21.     echo "时间已成功同步至: $(date)"
  22.   else
  23.     echo "设置系统时间失败。"
  24.   fi
  25. else
  26.   echo "从NTP服务器获取时间失败。"
  27. fi
复制代码

作者: klfvbfsui    时间: 2024-3-6 08:35
对啊,用gpt很快的
作者: yaoruisheng    时间: 2024-3-6 08:36
Sam_Edward 发表于 2024-3-6 08:27
没玩过盒子,不明白为什么要同步,另外以下是chatgpt 优化过的代码,你自己看对不对,不知道你要用于做什么 ...

能否使用nc命令创建udp连接?
作者: x2009again    时间: 2024-3-6 08:42
我以前用的这个
  1. date -s "$(wget -qSO- --max-redirect=0 google.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z"
复制代码

作者: Sam_Edward    时间: 2024-3-6 08:42
yaoruisheng 发表于 2024-3-6 08:36
能否使用nc命令创建udp连接?

要使用nc(Netcat)通过UDP发送NTP请求并接收响应的完整示例,首先需要注意,由于NTP响应是二进制格式的,处理这种响应需要一定的二进制到十进制的转换。以下是一个示例脚本,这个脚本发送NTP请求到一个NTP服务器,并尝试解析返回的时间戳。

请注意,这个脚本仅作为示例提供,可能需要根据实际的NTP服务器响应进行调整。该脚本的目的是展示如何使用nc发送UDP包,并非专门用于处理NTP协议。

  1. #!/bin/bash

  2. # NTP服务器和端口
  3. NTP_SERVER="ntp.tencent.com"
  4. NTP_PORT=123

  5. # 构造NTP请求数据包
  6. NTP_PACKET="\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

  7. # 发送NTP请求并接收响应
  8. RESPONSE=$(echo -ne "$NTP_PACKET" | nc -u -w 2 $NTP_SERVER $NTP_PORT | od -An -N4 -tu4 -j40)

  9. # 转换响应为Unix时间戳
  10. if [ ! -z "$RESPONSE" ]; then
  11.   # 从NTP时间(从1900年开始的秒数)转换为Unix时间戳(从1970年开始的秒数)
  12.   UNIX_TIME=$(($RESPONSE-2208988800))
  13.   # 设置系统时间(需要root权限)
  14.   # sudo date -s "@$UNIX_TIME"
  15.   echo "NTP time: $RESPONSE, Unix time: $UNIX_TIME"
  16. else
  17.   echo "Failed to receive a response from the NTP server."
  18. fi
复制代码


此脚本的关键点包括:

    构造NTP请求: NTP请求是一个特定格式的数据包,这里简化了构造方法,只包含最基本的字段。
    发送请求并接收响应: 通过nc命令以UDP模式发送请求到NTP服务器,并设置超时为2秒。响应数据通过管道传给od命令,以便解析。
    解析响应: 使用od命令处理二进制响应,提取出NTP时间戳。这里使用的是简化处理,实际响应可能包含更多信息。
    转换时间戳: 将NTP时间戳转换为Unix时间戳。NTP时间戳的起点是1900年,Unix时间戳的起点是1970年。

注意:

    为了实际设置系统时间,你需要以root用户执行脚本,或者使用sudo来运行date命令,这里为了安全考虑,设置时间的命令被注释掉了。
    确保你的环境中已经安装了nc和od工具。
    根据你的具体环境和NTP服务器的响应,可能需要调整解析响应部分的逻辑。
作者: yaoruisheng    时间: 2024-3-6 08:50
Sam_Edward 发表于 2024-3-6 08:42
要使用nc(Netcat)通过UDP发送NTP请求并接收响应的完整示例,首先需要注意,由于NTP响应是二进制格式的 ...

谢谢啊!
作者: acm    时间: 2024-3-6 08:52
NTP很大???
作者: Sam_Edward    时间: 2024-3-6 08:54
yaoruisheng 发表于 2024-3-6 08:50
谢谢啊!

没事
作者: btpanel    时间: 2024-3-6 08:57
https://www.baota.me/post-214.html
作者: yaoruisheng    时间: 2024-3-6 08:57
acm 发表于 2024-3-6 08:52
NTP很大???

需要安装一堆依赖。
作者: yaoruisheng    时间: 2024-3-6 08:58
x2009again 发表于 2024-3-6 08:42
我以前用的这个

这个也是可以的,不过google国内无法访问就是了。
作者: yaren    时间: 2024-3-6 09:08
Sam_Edward 发表于 2024-3-6 08:42
要使用nc(Netcat)通过UDP发送NTP请求并接收响应的完整示例,首先需要注意,由于NTP响应是二进制格式的 ...

这个是哪个gpt工具?
作者: Sam_Edward    时间: 2024-3-6 09:09
yaren 发表于 2024-3-6 09:08
这个是哪个gpt工具?

官方的
作者: zhsh    时间: 2024-3-6 09:56
现在AI用处还是很大的,对于代码直接就可以进行解读

date -s "$(wget -qSO- --max-redirect=0 google.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z"
这段代码的作用是通过wget命令从google.com获取当前日期和时间,并将其设置为系统的日期和时间。让我详细解释一下:

wget -qSO- --max-redirect=0 google.com: 这部分使用wget命令来请求google.com网站的内容,-q参数表示以安静模式(不输出多余信息)执行,-S参数表示显示服务器的响应头信息,-O-参数表示输出到标准输出。

2>&1: 将标准错误输出重定向到标准输出,因此任何错误信息都会被包含在wget的输出中。

grep Date:: 通过grep命令来筛选包含"Date:"的行,这里是为了找到HTTP响应头中的日期信息。

cut -d' ' -f5-8: 使用cut命令来提取HTTP响应头中日期信息的具体部分,-d' '表示使用空格作为分隔符,-f5-8表示提取第5个字段到第8个字段,即日期的具体文本。

Z: 在最后加上Z表示将提取到的日期时间字符串标记为UTC时间。

date -s: 最后使用date -s命令将提取到的日期时间字符串设为系统日期时间。

总而言之,这段代码的作用是从google.com获取日期和时间信息,然后将其设置为系统的日期和时间。


作者: yaoruisheng    时间: 2024-3-6 11:55
Sam_Edward 发表于 2024-3-6 08:27
没玩过盒子,不明白为什么要同步,另外以下是chatgpt 优化过的代码,你自己看对不对,不知道你要用于做什么 ...

但是这个脚本有问题,shell变量无法存储nul
作者: Sam_Edward    时间: 2024-3-6 12:12
yaoruisheng 发表于 2024-3-6 11:55
但是这个脚本有问题,shell变量无法存储nul

您的脚本尝试通过Bash脚本与NTP服务器进行通信,从而同步时间。然而,确实如您所说,Bash中的变量处理对于包含null(\0)的数据有局限性,这会影响从NTP响应中正确提取时间戳。

在Bash中处理包含null字符的数据时,常见的问题是null字符会导致字符串的提前终止,因为Bash和许多其他工具都是用C语言编写的,而C语言中的字符串是以null字符为结束标志的。这意味着,当Bash遇到null字符时,它会认为字符串到此为止。

您的脚本中,尝试通过read -n 48 response来读取NTP响应是一个很好的尝试,但是处理二进制数据(尤其是包含null字符的)时,read命令和Bash变量都可能无**确处理。

一个更稳妥的解决方案是使用像xxd(或其他能处理二进制数据的工具)将二进制数据转换成十六进制字符串,然后再进行解析。虽然这种方法可能需要更复杂的处理逻辑,但它能避免处理含有null字符的字符串时遇到的问题。

举个例子,您可以使用下面的方法来安全地处理NTP响应:

    使用dd或cat命令读取NTP响应,并立即通过管道传递给xxd或类似工具转换为十六进制。
    解析十六进制数据以提取时间戳。

这里是一个简化的例子,演示如何使用xxd来处理响应:
  1. # 使用`dd`命令从NTP响应中读取48个字节的数据
  2. response=$(dd bs=48 count=1 <&5 2>/dev/null | xxd -p -c 48)

  3. # 假设我们得到的十六进制数据存储在$response中,然后进行解析
  4. # 这里仅作为展示,实际解析逻辑可能需要根据NTP协议详细说明进行调整
复制代码


完整修改后的代码:
  1. #!/bin/bash

  2. # NTP服务器地址和端口
  3. NTP_SERVER="ntp.tencent.com"
  4. NTP_PORT=123

  5. # 创建UDP连接
  6. exec 5<>/dev/udp/${NTP_SERVER}/${NTP_PORT}

  7. # 发送NTP请求包 (根据NTP协议格式)
  8. printf '\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' >&5

  9. # 使用dd命令从UDP连接中读取NTP响应,并通过xxd转换为十六进制
  10. response_hex=$(dd bs=48 count=1 <&5 2>/dev/null | xxd -p -u -c 48)

  11. # 检查是否收到响应
  12. if [ -z "$response_hex" ]; then
  13.   echo "从NTP服务器获取时间失败。"
  14.   exit 1
  15. fi

  16. # 将十六进制响应转换为二进制,并提取时间戳(从第40个字节开始的4个字节)
  17. time_hex=${response_hex:40*2:8}
  18. # 使用awk将十六进制时间戳转换为十进制
  19. time_dec=$(echo $time_hex | awk '{print strtonum("0x"$0)}')

  20. # NTP时间戳起始于1900年,Unix时间戳起始于1970年
  21. # 需要从NTP时间戳减去差值(2208988800秒)
  22. unix_time=$((time_dec - 2208988800))

  23. # 设置系统时间
  24. if date -s "@$unix_time" > /dev/null 2>&1; then
  25.   echo "时间已成功同步至: $(date)"
  26. else
  27.   echo "设置系统时间失败。"
  28. fi

  29. # 关闭UDP连接
  30. exec 5<&-
  31. exec 5>&-
复制代码

请注意,根据您的系统配置和权限,直接设置系统时间可能需要管理员权限。此外,处理十六进制数据和时间戳转换时,请确保按照NTP协议的详细说明进行调整。
作者: HOH    时间: 2024-3-6 12:17
curl一下date就行了,两行的事情,还整什么ntp莫名其妙
作者: 随便起个名字    时间: 2024-3-6 12:52
都是用ntp客户端 没想到同步时间还能这样搞
作者: yaoruisheng    时间: 2024-3-6 14:12
随便起个名字 发表于 2024-3-6 12:52
都是用ntp客户端 没想到同步时间还能这样搞

apt安装个客户端,需要一堆依赖。太占用空间了。
作者: x2009again    时间: 2024-3-7 08:27
yaoruisheng 发表于 2024-3-6 08:58
这个也是可以的,不过google国内无法访问就是了。

你自己换成taobao.com就可以了
作者: aru    时间: 2024-3-7 08:38
本帖最后由 aru 于 2024-3-7 08:40 编辑
yaoruisheng 发表于 2024-3-6 08:57
需要安装一堆依赖。


如果你的机器用了systemd,那我推荐 systemd-timesyncd ,非常小巧
apt update && apt -y install systemd-timesyncd &&  systemctl enable systemd-timesyncd && systemctl start systemd-timesyncd

Debian 9、Ubuntu 16.04 开始就用了systemd




欢迎光临 全球主机交流论坛 (https://loc.442266.xyz/) Powered by Discuz! X3.4