"IFS=!"的确切用途和含义是什么

  • 本文关键字:是什么 IFS shell unix sh
  • 更新时间 :
  • 英文 :


我试图了解IFS的用法,但有些东西我找不到任何信息。

我的示例代码:

#!/bin/sh
# (C) 2016 Ergin Bilgin
IFS=!
for LINE in $(last -a | sed '$ d')
do
    echo $LINE | awk '{print $1}'
done
unset IFS

我使用此代码逐行打印最后一个用户。我完全理解 IFS 的用法,在这个例子中,当我使用默认 IFS 时,它会在我的循环中逐字读取。当我使用IFS=!时,它会按照我的意愿逐行阅读。这里的问题是我在任何地方都找不到关于那个"!"的任何信息。我不记得我从哪里学到的。当我在谷歌上搜索实现相同的行为时,我看到其他值通常是字符串。

那么,这个"!"的含义是什么,它如何给我我希望的结果?

谢谢

IFS=!只是为IFS设置一个不存在的值,以便您可以逐行迭代输入。话虽如此,不建议在这里使用 for 循环,最好在这样的while循环中使用 read 来打印第一列,即用户名:

last | sed '$ d' | while read -r u _; do
   echo "$u"
done

如您所知,如果last的输出有!,脚本将拆分该字符上的输入行。

last的输出格式不是标准化的(例如,在POSIX中不是),但是您不太可能找到一个系统,其中第一列包含除发起操作的任何名称之外的任何内容。 例如,我看到这个:

tom      pts/8        Wed Apr 27 04:25   still logged in    michener.jexium-island.net
tom      pts/0        Wed Apr 27 04:15   still logged in    michener.jexium-island.net
reboot   system boot  Wed Apr 27 04:02 - 04:35  (00:33)     3.2.0-4-amd64
tom      pts/0        Tue Apr 26 16:23 - down   (04:56)     michener.jexium-island.net

继续

reboot   system boot  Fri Apr  1 15:54 - 19:03  (03:09)     3.2.0-4-amd64
tom      pts/0        Fri Apr  1 04:34 - down   (00:54)     michener.jexium-island.net
wtmp begins Fri Apr  1 04:34:26 2016

使用 Linux,以及其他机器上的不同日期格式、来源等。

通过设置IFS=!,脚本将字段分隔符设置为一个在last的输出中不太可能出现的值,所以每一行都被读入LINE而不拆分它。 通常,行在空格上拆分。

但是,如您所见,last 的输出通常使用空格来分隔列,并且它被馈送到 awk 中,无论如何都会拆分行 — 带有空格。 脚本可以通过多种方式简化,例如:

#!/bin/sh
for LINE in $(last -a | sed -e '$ d' -e 's/ .*//')
do    
    echo $LINE
done

如果登录次数不足以超过您的命令行,则(从问题中的示例开始)就足够了。 在检查last输出的变化时,我注意到一台机器有大约 9800 行,来自几年前。 (在这种情况下,不使用for循环的其他常见动机是不可信的)。 作为管道:

#!/bin/sh
last -a | sed -e 's/ .*//' -e '/^$/d' | while IFS= read LINE
do
    echo $LINE
done

我更改了 sed 表达式(OP 可能从某个地方复制,例如 Bash - 从文件中删除最后一行),因为它不起作用。

最后,没有必要使用 last-a选项,因为它提供的所有其他信息都将被丢弃。

最新更新