Linux 上密码哈希的第 6 个字符是什么,为什么它经常是斜杠?

ins*_*ure 86 password shadow

在 Linux 上,存储在 中的密码哈希的第六个字符是/etc/shadow什么?

在我的 puppy style linux box 上,如果我尝试使用shufand生成 100 个随机密码/dev/urandom,那么第六个字符/大约是一半的时间。

我的问题不是用于生产目的,因为我每次都从 CD 启动它。这是否意味着我的系统在某些方面配置错误或不安全?

我运行文件shuf,看看它是否是一个busybox链接。

file /usr/bin/shuf

    shuf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped
Run Code Online (Sandbox Code Playgroud)

我不认为这shufbusybox这里的链接。

ls -l /usr/bin/shuf

    -rwxr-xr-x 1 root root 41568 Mar  7  2015 /usr/bin/shuf
Run Code Online (Sandbox Code Playgroud)

尽管

ls -l /bin/wget

    lrwxrwxrwx 1 root root 14 Apr 29 03:49 wget -> ../bin/busybox
Run Code Online (Sandbox Code Playgroud)

这是我所做的一个粗略的想法:

# ! / b i n / b a s h
##  don't try this on any real computer
##  this is not a production script, it is just psuedo code
##  with pseudo results to illustrate a point

##  for this run of 100 ?random? passwords,
##  46 of the 6th character of the hash stored in
##  '/ect/shadow' were '/'

function is_this_really_a_random_password () {
PERHAPS_RANDOM=''
for (( Z=0 ; Z<=8 ; Z++ )) do
PERHAPS_RANDOM="$PERHAPS_RANDOM$( shuf --head-count=1 --random-source=/dev/urandom $FILE_OF_SAFE_CHARACTERS )"
done
echo "$USER_NAME:$PERHAPS_RANDOM" | chpasswd
}

rm sixth-character-often-forward-slash.txt
for (( I=1; I<=100; I++ )) do
is_this_really_a_random_password
grep --regexp=root /etc/shadow | cut --characters=-40 >> sixth-character-often-forward-slash.txt
done
Run Code Online (Sandbox Code Playgroud)
    root:$5$56YsS//DE$HasM6O8y2mnXbtgeE64zK
    root:$5$ho8pk/4/A6e/m0eW$XmjA5Up.0Xig1e
    root:$5$jBQ4f.t1$vY/T/1kX8nzAEK8vQD3Bho
    root:$5$BJ44S/Hn$CsnG00z6FB5daFteS5QCYE
    root:$5$Jerqgx/96/HlV$9Wms5n1FEiM3K93A8
    root:$5$qBbPLe4zYW$/zXRDqgjbllbsjkleCTB
    root:$5$37MrD/r0AlIC40n6$8hplf2c3DgtbM1
    root:$5$.4Tt5S6F.3K7l7E$dAIZzFvvWmw2uyC
    root:$5$A4dX4ZlOoE$6axanr4GLPyhDstWsQ9B
    root:$5$HXAGhryJ/5$40tgmo7q30yW6OF7RUOE
    root:$5$EzNb9t5d$/nQEbEAQyug7Dk9X3YXCEv
    root:$5$HHS5yDeSP$LPtbJeTr0/5Z33vvw87bU
    root:$5$sDgxZwTX5Sm$6Pzcizq4NcKsWEKEL15
    root:$5$FK1du/Paf/$hAy8Xe3UQv9HIpOAtLZ2
    root:$5$xTkuy/BLUDh/N$/30sESA.5nVr1zFwI
    root:$5$PV4AX/OjZ$VU8vX651q4eUqjFWbE2b/
    root:$5$iDuK0IUGijv4l$cdGh8BlHKJLYxPB8/
    root:$5$0DEUp/jz$JBpqllXswNc0bMJA5IFgem
    root:$5$Wz3og/W3Jra/WKA.$6D7Wd4M1xxRDEp
    root:$5$ntHWB.mC3x$Kt4DNTjRZZzpbFvxpMxP
    root:$5$g/uEc/cq$Ptlgu8CXV.vrjrmuok9RRT
    root:$5$/XAHs/5x$Z9J4Zt4k6NxdjJ27PpLmTt
    root:$5$mgfbZeWD0h/$UDGz8YX.D85PzeXnd2K
    root:$5$f4Oh3/bF2Ox/eN$xt/Jkn0LxPnfKP8.
    root:$5$J0mZZXGJG7/v$e16VxghNvZZKRONown
    root:$5$SNza9XFl9i$Qq7r/N6Knt2j74no8H0x
    root:$5$aFCu//xiL$Ocn9mcT2izcnm3rUlBOJg
    root:$5$kMkyos/SLZ/Mm6$wNYxZ9QeuJ8c8T.o
    root:$5$ujXKC/Xnj0h/nQ$PUmePvJZr.UXmTGK
    root:$5$wtEhA/YKaTKH$6VCSXUiIdsfelkCYWV
    root:$5$I1taRlq59YZUGe$4OyIfByuvJeuwsjM
    root:$5$N54oH//j4nbiB$K4i6QOiS9iaaX.RiD
    root:$5$ps8bo/VjPGMP0y4$NTFkI6OeaMAQL7w
    root:$5$IRUXnXO8tSykA8$NatM5X/kKHHgtDLt
    root:$5$VaOgL/8V$m45M9glUYnlTKk8uCI7b5P
    root:$5$/lPDb/kUX73/F3$jJL.QLH5o9Ue9pVa
    root:$5$/sHNL/tVzuu//cr$QasvQxa02sXAHOl
    root:$5$hGI.SMi/7I$fYm0rZP0F5B2D1YezqtX
    root:$5$WsW2iENKA$4HhotPoLRc8ZbBVg4Z5QW
    root:$5$cN6mwqEl$q5S3U85cRuNHrlxS9Tl/PC
    root:$5$wwzLR/YMvk5/7ldQ$s3BJhq5LyrtZww
    root:$5$GUNvr/d15n8/K$CiNHwOkAtxuWJeNy1
    root:$5$nGE75/8mEjM/A$pD/84iLunN/ZNI/JK
    root:$5$77Dn2dHLS$d5bUQhTz.OU4UA.67IGMB
    root:$5$EWrI//1u$uubkPk3YhAnwYXOYsvwbah
    root:$5$Hzfw1UCudP/N/U$Rjcdzdbov1YgozSJ
    root:$5$2y8CKTj.2eTq$7BEIgMWIzAJLl1SWBv
    root:$5$lcWsD/42g8zEEABA$r/vGxqqUZTkJ0V
    root:$5$LPJLc/Xz$tnfDgJh7BsAT1ikpn21l76
    root:$5$ucvPeKw9eq8a$vTneH.4XasgBIeyGSA
    root:$5$Fwm2eUR7$ByjuLJRHoIFWnHtvayragS
    root:$5$yBl7BtMb$KlWGwBL6/WjgHVwXQh9fJS
    root:$5$1lnnh2kOG$rdTLjJsSpC3Iw4Y6nkPhq
    root:$5$WfvmP6cSfb066Z$1WvaC9iL11bPCAxa
    root:$5$qmf/hHvalWa4GE25$m3O2pdu25QBCwU
    root:$5$4P.oT/9HQ$Ygid4WXi0QCEObLVNsqFZ
    root:$5$FNr4Bkj56Y$38mG7mKV0mdb1PMCxrVd
    root:$5$hoNcyURtV$aTidBWHjngc1I0vUTi5bB
    root:$5$rzHmykYT$ATiXdUDUvUnB2fNMUQgwvE
    root:$5$o11Yb/ZQv2/k3wg9$5yShpVejDBk6HB
    root:$5$REPGN//y9H$awpPmUvCqvi6Bd/6bQxF
    root:$5$HbAEY/djXJx$y56GhMwavd7xTQ.jPg6
    root:$5$3T1k5.LZUcy$Cup.LM5AnaBTIaJtBnF
    root:$5$wXaSC/P8bJ$y/0DoYJVjaP09O6GWiki
    root:$5$YuFfY8QPqm/dD$IIh0/tyn.18xEBl5Y
    root:$5$uTTBpjsKG//3Et8$9ibN9mVwSeVyOI4
    root:$5$dASlMLzbVbFMnZ$N4uGBwGHhdg93z/V
    root:$5$03.FA/LnRBb.k7Zl$XOHU2ZlHkV9oz9
    root:$5$2zL1p/VDCi$/QRT7Bo3cZ3Rxb8Y7ddo
    root:$5$0NpZqZs/qt/jIv.$8W/TTM3Gy2UMOWy
    root:$5$a4SXynoro7ucT$qFM2C79QJ15jQ0ZlL
    root:$5$RL0Eg/jroH8/ONP$EzceXz.pz74k104
    root:$5$O3R5V/n1$U.mmCTbpID8xMXbvtzd4ch
    root:$5$0T2nVrv/P/xaRwUD$YVm17XF8kTsL0f
    root:$5$2bRwMNIXobZwn$Q228FJqg6/iRCe9GQ
    root:$5$PyYgL/axfgj/$uaL5y/kdzU4Kzi.JlB
    root:$5$A6QtfJdJ4Gwvx4$d4PA5AJ0806NzRnm
    root:$5$H8Mta5LDgGXp$QGdOJh.bFWgR3L719Z
    root:$5$H06URjv4BtOAbA$EJs1mZYhdKIVgCmn
    root:$5$OeB.O/GrmFB/az$SoE759KE9WIE17Uf
    root:$5$huiB9/sk$el3XMf7SGX81LnD3.SaF8J
    root:$5$fO7tfM.fjdSHA8G6$s.QIjfNniCzFdU
    root:$5$32at3SQJAD/xlw$HbXmBLVXTTyZfxQv
    root:$5$FHBFL/QdFl$FMipxpW0HlEFUIAr7IxF
    root:$5$sHvKf/M5OPdBuZZ$dz4qLOkTLGeCINX
    root:$5$hw4Vu/e34$/82lXu7ISrse.Ihk.qbqT
    root:$5$k1JOy/jRWZ$30YSk7kbhdKOjfDaiWVf
    root:$5$MnX.LUzqrB/B2$JuwqC.SmKFnMUWkEf
    root:$5$arRYf/PG$Xw6PpZNFO656p.Eb636iLt
    root:$5$5op/p8Hqs5$Nj2jA0Qxm80aG4fHW3oz
    root:$5$VHIT9/8yzZ$CpIK4ODps78GcqcsgiMT
    root:$5$.AlH7jBJoh/8$sjuVt.PcRH.vyvB3og
    root:$5$f7Ewinqm$nrJ2p/hKTuiEK//IfCTjth
    root:$5$N.dv/VCvrCADg$peSXfo35KN1dmbw/n
    root:$5$PSc4W./54l/SroH$CFFVOHRYK.Jj8Sp
    root:$5$8UBP3f4IcnAd/N1/$P.ud49qTStQ7Lw
    root:$5$qnXsZ/NlLZh/$nlaQVTS3FCJg1Jb2QG
    root:$5$xOpbbBqENR/7$boYJQzkCkZhRf7Uicf
    root:$5$V93tjZhzT$LrsIZWZmYo4ocRUvCixO6
    root:$5$1MVz8/lf5oC/$rUKpnX23MhFx4.y2ZS
Run Code Online (Sandbox Code Playgroud)

大约一半的第 6 个哈希字符是/

cat sixth-character-often-forward-slash.txt | cut --character=14 | sort


    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    /
    .
    .
    .
    .
    2
    5
    6
    8
    8
    B
    d
    D
    e
    e
    E
    f
    H
    I
    j
    j
    j
    J
    k
    k
    K
    l
    L
    M
    M
    n
    n
    N
    q
    r
    r
    r
    s
    S
    S
    t
    t
    T
    U
    U
    U
    U
    V
    w
    x
    X
    X
    X
    Z
    Z
    Z
Run Code Online (Sandbox Code Playgroud)

ilk*_*chu 89

哈希格式和来源

密码哈希的格式为$<type>$<salt>$<hash>,其中<type> 5是基于 SHA-256 的哈希。盐通常至少有 8 个字符(并且在问题的示例中),因此第六个字符是盐的一部分。

这些哈希值可能是由影子工具套件的某个版本(shadowDebianshadow-utils中的src 包,CentOS 中)生成的

我试图找出为什么代码会偏向斜线。(感谢@thrig 最初挖掘了代码。)

TLDR: 这有点有趣,但无所谓。


生成盐的代码

在 中libmisc/salt.c,我们找到了在循环gensalt中调用的函数l64a

strcat (salt, l64a (random()));
do {
       strcat (salt, l64a (random()));
} while (strlen (salt) < salt_size);
Run Code Online (Sandbox Code Playgroud)

循环从 中获取一个随机数random(),将其转换为一段字符串,并将其连接到形成盐的字符串。重复直到收集到足够的字符。

l64a然而,发生的事情更有趣。内部循环从输入值(来自random())一次生成一个字符:

for (i = 0; value != 0 && i < 6; i++) {
    digit = value & 0x3f;

    if (digit < 2) {
        *s = digit + '.';
    } else if (digit < 12) {
        *s = digit + '0' - 2;
    } else if (digit < 38) {
        *s = digit + 'A' - 12;
    } else {
        *s = digit + 'a' - 38;
    }

    value >>= 6;
    s++;
}
Run Code Online (Sandbox Code Playgroud)

循环的第一行 ( digit = value & 0x3f) 从输入值中选取六位,if子句将这些位形成的值转换为字符。(.对于零,/对于一,0对于二等)

l64a采用 along但输出的值random()仅限于RAND_MAX,在 glibc 上似乎是 2147483647 或 2^31 - 1。因此,到达的值l64a是 31 位的随机数。通过一次取 6 位或 31 位值,我们得到五个合理均匀分布的字符,再加上仅来自一位的第六个字符!

但是,由 生成的最后一个字符l64a不能是 a .,因为循环也有条件value != 0, 而不是 a.作为第六个字符,l64a只返回五个字符。因此,一半的时间,第六个字符是 a /,一半的时间l64a返回五个或更少的字符。在后一种情况下,跟随l64a也可以在第一个位置生成斜杠,所以在全盐中,第六个字符应该是斜杠的一半多一点。

该代码还具有随机化盐长度的功能,它是 8 到 16 个字节。对斜杠字符的相同偏见也会发生在进一步调用中,l64a这将导致第 11 个和第 12 个字符也比其他任何字符更频繁地使用斜杠。问题中提出的 100 种盐在第 6 位有 46 条斜线,在第 11 和第 12 位分别有 13 和 15 条斜线。(略少于一半的盐少于 11 个字符)。

在 Debian 上

在 Debian 上,我无法chpasswd像问题中所示那样用直线重现这个。但chpasswd -c SHA256表现出相同的行为。根据手册,没有 的默认操作-c是让 PAM 处理散列,因此显然 Debian 上的 PAM 至少使用不同的代码来生成盐。但是,我没有查看任何发行版上的 PAM 代码。

(此答案的先前版本表示该效果未出现在 Debian 上。这是不正确的。)

盐的意义和要求

不过,这有关系吗?正如@RemcoGerlich 所评论的,这几乎只是一个编码问题。它将有效地将一些盐位固定为零,但在这种情况下这可能不会产生重大影响,因为这些位的起源是对srandomin 的调用seedRNG

srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ());
Run Code Online (Sandbox Code Playgroud)

这是使用当前时间为 RNG 设置种子的古老习俗的一种变体。(tv_sectv_usec是当前时间的秒和微秒,getpid()如果正在运行进程,则给出进程 id。)由于时间和 PID 不是很不可预测,这里的随机性数量可能不会大于编码所能容纳的数量。

时间和 PID 不是您想用来创建密钥的东西,但对于盐来说可能是不可预测的。Salts必须是不同的,以防止通过一次计算暴力测试多个密码哈希,但也应该是不可预测的,以防止或减慢有针对性的预计算,这可用于缩短从获取密码哈希到获取实际密码的时间.

即使有一些小问题,只要算法不会为不同的密码生成相同的盐,就应该没问题。它似乎没有,即使在循环中生成几十个,如问题中的列表所示。

此外,有问题的代码除了为密码生成盐外不用于任何其他用途,因此不会对其他地方的问题产生影响。

对于盐,也见,例如这对堆栈溢出这对security.SE

结论

总之,你的系统没有任何问题。确保您的密码是好的,而不是在不相关的系统上使用更值得考虑。

  • @RemcoGerlich 这是偏见的教科书定义。因为并非所有位都被统一考虑。这对于在非盐环境中使用此代码的其他项目也确实有影响。作为 /etc/shadow 密码中的盐,它不是一个引人注目的问题,但它令人担忧。 (9认同)
  • 您误解了您链接到的 security.SE 帖子,并且您链接到的 SO 帖子的公认答案是错误的,这就是为什么还有另一个答案与超过 10 倍的选票相矛盾。“盐只需要不同”的说法是不正确的;盐的*熵*很重要,因为这决定了它增加预计算难度的程度。由于偏差,这些盐的熵比它们的长度要小。不是*关键*少,而是少5位。这是一个缺陷。 (4认同)
  • 所以实际的盐没有偏见,它只是它们编码方式的产物,没有任何安全隐患,对吗? (2认同)

thr*_*rig 27

根据crypt(3)手册,该字符是盐的一部分。鉴于盐的长度($5$ID 和后续之间的字符串$)因显示的哈希而异,我不确定从该特定列中为几个密码选择随机字符说明了什么。

在另一方面中,/ 相当更普遍(102个实例)在整个相对于其他可能接受字符(约18)的盐,这样的东西在chpasswd确实出现了有利于在盐该字符;

for x in `seq 1 100000`; do
  echo testacct:asdfasdfasdf | chpasswd -c SHA256
  awk -F: '/testacct/{print $2}' /etc/shadow | awk -F\$ '{print $3}' >> salts
done
perl -nle 'print for m/(.)/g' salts | sort | uniq -c | sort -nr | head -5
Run Code Online (Sandbox Code Playgroud)

在 RedHat EL 6 系统上运行:

   1006 /
    195 X
    193 U
    193 q
    193 e
Run Code Online (Sandbox Code Playgroud)

而且,是的,中的代码shadow-utils-4.1.5.1-5.el6表现出/可能使字典攻击更容易的偏见:

#include <sys/time.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

// these next two borrowed from libmisc/salt.c of shadow-4.1.5.1 from
// Centos 6.8 RPM at http://vault.centos.org/6.8/os/Source/SPackages/shadow-utils-4.1.5.1-5.el6.src.rpm
char *l64a(long value)
{
    static char buf[8];
    char *s = buf;
    int digit;
    int i;

    if (value < 0) {
        abort();
    }

    for (i = 0; value != 0 && i < 6; i++) {
        digit = value & 0x3f;

        if (digit < 2) {
            *s = digit + '.';
        } else if (digit < 12) {
            *s = digit + '0' - 2;
        } else if (digit < 38) {
            *s = digit + 'A' - 12;
        } else {
            *s = digit + 'a' - 38;
        }

        value >>= 6;
        s++;
    }

    *s = '\0';

    return (buf);
}

static void seedRNG(void)
{
    struct timeval tv;
    static int seeded = 0;

    if (0 == seeded) {
        (void) gettimeofday(&tv, NULL);
        srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
        seeded = 1;
    }
}

int main(void)
{
    seedRNG();
    for (int x = 0; x < 1000; x++) {
        printf("%s\n", l64a(random()));
    }

    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

结果是:

% ./salttest | perl -nle 'print for m/(.)/g' | sort | uniq -c | sort -nr | head -3
 593 /
  96 8
  93 3
Run Code Online (Sandbox Code Playgroud)

然后使用最新https://github.com/shadow-maint/shadow/blob/master/libmisc/salt.c 中的相同例程,我们发现仍然存在对/. 所以呃,是的,这是一个应该修补的错误,所以/不太受青睐,因为理想情况下,salt 字符的权重应该相等。

  • 盐中的偏差本身并无害(不像密钥中的偏差)。盐只需要是唯一的,它不需要是不可预测的。由 MAC 地址(或唯一标识机器的东西)和时间(假设时钟不倒退)组成的盐就可以了。“理想情况下,salt 字符的权重应该相等”的说法是错误的。 (14认同)
  • 但是,如果 salt 生成不当,则不会激发对其余加密代码的信心。 (8认同)
  • @thrig 不,可预测的盐对字典攻击没有帮助,因为盐对字典攻击没有帮助。盐有助于针对多个帐户的攻击(更准确地说:多个散列 - 同一帐户上的连续散列),为此,重要的是盐对于不同的帐户是不同的。盐的不可预测性是无关紧要的,只有它们的独特性(实际上,即使是低重复计数也足够了)。 (7认同)
  • 对于盐,它们需要是全球唯一的。他们不需要是随机的,也不需要是秘密的。但它们确实需要是全球唯一的。事实证明,如果您尝试增加计数器或创建一些奇特的确定性算法,这比仅从 OS RNG 中获取随机位更难做到。如果您随机生成 16 个 base64 字符,那么您有 /64^16 的碰撞机会。当然,盐的全部意义,就是让彩虹表攻击无果而终。在这种情况下,16 个字符的 base64 盐空间将是 64^15 &lt; n &lt; 64^16。不是一个showstopper,但很容易修复。 (4认同)
  • @MontyHarder Entropy 不是一种汽油——你不消耗它,就像你不消耗温度一样。这是对机器不可预测状态的猜测,就像温度是对封闭体积中气体分子能量的猜测。无论如何,您应该从 [/dev/urandom](http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/) 中提取,在正确播种后,它与真正的随机数无法区分噪音。此外,滚动您自己的设计而不是从 RNG 中获取数据几乎可以保证您自己在脚下开枪。只需使用/dev/urandom。 (4认同)
  • Gilles 所说的关键点是,salt 生成器有很大的空间很差,但不会差到在同一个影子文件中(或攻击者可能同时攻击的多个系统之间)发生实际冲突的程度)。这就是盐起作用的全部。击败[彩虹表](https://en.wikipedia.org/wiki/Rainbow_table)只需要一点随机性。 (3认同)
  • (好吧,如果知道 salt 有一个非常小的优势,即攻击者可以在找到散列之前开始破解密码,但这是微不足道的,在这方面,即使是分布很差的 salt 也足够了。)见 http: //security.stackexchange.com/questions/211/how-to-securely-hash-passwords ,http://security.stackexchange.com/questions/17421/how-to-store-salt 和 [security .se]。 (2认同)

Aar*_*nce 5

mkpasswd(1)可能是 的前端crypt(3),但它与 running 不同chpasswd(1),它是 CentOS 上“shadow-utils”包和 Debian 上“passwd”包的一部分。相反,您应该比较苹果与苹果。考虑以下脚本:

#!/bin/bash

# This repeatedly changes a `saltuser' password
# and grabs the salt out of /etc/shadow.
# Requires root and the existence of `saltuser' user.

if [ $EUID -ne 0 ]; then
    echo "This script requires root access to read /etc/shadow."
    exit 1
fi

grep -q saltuser /etc/passwd

if [ $? -ne 0 ]; then
    echo "This script requires the 'saltuser' to be present."
    exit 2
fi

: > /tmp/salts.txt

for i in {1..1000}; do
    PW=$(tr -cd '[[:print:]]' < /dev/urandom | head -c 64)
    echo "saltuser:${PW}" | chpasswd -c SHA256 -s 0 2> /dev/urandom
    awk -F '$' '/^saltuser/ {print $3}' /etc/shadow >> /tmp/salts.txt
done

while read LINE; do
    # 6th character in the salt
    echo ${LINE:5:1}
done < /tmp/salts.txt | sort | uniq -c | sort -rn
Run Code Online (Sandbox Code Playgroud)

Debian Sid 的输出:

512 /
 14 T
 13 W
 13 v
 13 t
 12 x
 12 m
 12 d
 11 p
 11 L
 11 F
 11 4
 10 s
 10 l
 10 g
 10 f
 10 7
 10 6
  9 Z
  9 w
  9 N
  9 H
  9 G
  9 E
  9 A
  8 Y
  8 X
  8 r
  8 O
  8 j
  8 c
  8 B
  8 b
  8 9
  7 u
  7 R
  7 q
  7 P
  7 M
  7 k
  7 D
  6 z
  6 y
  6 U
  6 S
  6 K
  6 5
  5 V
  5 Q
  5 o
  5 J
  5 I
  5 i
  5 C
  5 a
  5 3
  4 n
  4 h
  4 e
  4 2
  4 0
  4 .
  3 8
  3 1
Run Code Online (Sandbox Code Playgroud)

CentOS 7 的输出:

504 /
 13 P
 13 B
 12 s
 12 Z
 11 e
 11 Y
 11 O
 11 L
 11 G
 10 w
 10 u
 10 q
 10 i
 10 h
 10 X
 10 I
 10 E
  9 x
  9 g
  9 f
  9 W
  9 F
  9 C
  9 9
  9 8
  8 v
  8 t
  8 c
  8 b
  8 S
  8 H
  8 D
  8 0
  7 z
  7 y
  7 o
  7 k
  7 U
  7 T
  7 R
  7 M
  7 A
  7 6
  7 4
  7 1
  6 p
  6 d
  6 a
  6 Q
  6 J
  6 5
  6 .
  5 r
  5 m
  5 j
  5 V
  5 3
  5 2
  4 n
  4 l
  4 N
  4 K
  3 7
Run Code Online (Sandbox Code Playgroud)

所以,这个问题不是 CentOS 独有的,而是可能来自两个项目都来自的上游。

  • @someonewithpc 这是清空文件的 POSIX 方式。如果文件不存在,`touch(1)` 会创建一个文件,但如果它存在,则只更新修改后的时间戳。这不是清空文件的正确方法。`:&gt; file` 将保证它存在并且它是空的。 (2认同)