tail -n
从文件末尾获得$i
行,因此在第一个循环中您获得一行,在第二个循环中您获得两行,依此类推。最后四行并遍历它们,您可以使用while read
循环进行操作:
tail -n 4 /etc/passwd |
cut -d: -f1 |
while read -r user # "-r" prevents backslashes causing problems
do
echo "User: $user"
done
或者您可以使用AWK替换cut
和while read
循环:
tail -n 4 /etc/passwd |
awk -F: '{print "User:",$1}'
(对Gordon Davisson进行了改进)
,
@wjandrea已经解释了如何执行此操作;我将尝试解释为什么原版不起作用。我还将说明一种用于此类事情的重要调试技术:如果一个复杂的流程无法实现您想要的功能,请拆开它并单独运行各个部分,然后看看它们在做什么。
在这种情况下,循环的第一次迭代将按您期望的方式工作(它显示“ User:art101c40”),因此不必担心。让我们看第二遍迭代,其中i
= 2。替换该值后,它将运行命令:
echo User:$(tail -n 2 /etc/passwd | cut --delimiter=":" --fields="1")
因此,让我们遍历各个部分,看看它们的作用。首先,它运行tail -n 2 /etc/passwd
,它将打印/ etc / passwd的最后两行。大概是这样的:
art101c39:*:10139:99:Art 101 class 39:/home/art101c39:/bin/bash
art101c40:*:10140:99:Art 101 class 40:/home/art101c39:/bin/bash
请注意,它打印最后两行(tail -n 2
就是这样做的),因此它同时打印了art101c39和art101c40。这是整个问题的根源。
但让我们继续跟踪其行为。该输出通过cut --delimiter=":" --fields="1"
传递,该输出显示:
art101c39
art101c40
被$( )
捕获并用作echo
的参数。每个用户名都位于单独的行上,因此它们用换行符隔开,但是$( )
不在双引号中,因此容易进行分词。单词拆分将它根据空格(通常是空格,制表符和换行符)分成“单词”,因此每个用户名都只是一个单独的单词。本质上,它变成“ art101c39
”和“ art101c40
”。如果其中任何一个都具有文件名通配符,则外壳程序将尝试将它们转换为匹配文件列表;但是没有通配符,因此不会发生。然后将这些“单词”添加到echo
的参数中,得到:
echo User:art101c39 art101c40
echo
接收两个自变量“ User:art101c39
”和“ art101c40
”。像往常一样,它将这些粘贴在一起并在它们之间留出一个空格,然后打印结果。
类似的事情发生在第三次和第四次迭代中,tail
先打印三个然后是四个帐户,所有这些帐户都将通过其余的处理。
您可以通过在管道head
中添加tail -n $i /etc/passwd | head -n 1 | ...
直接解决此问题。这样,tail
将打印最后的$i
行,而head
将删除除第一行以外的所有行(文件末尾的第$i
条)。但是这种方法往往效率低下并且(IMO)过于笨拙。它涉及读取整个文件以从一行中选择一个字段。对于四行(帐户),您需要读取整个文件四次。如果您要从每个用户中选择两个字段,那将意味着读取文件八次。
通常有一种更简单,更好的方法来执行此操作,但这取决于实际目标。通常,您将运行一次tail
,然后处理该输出的常见方法包括:让awk -F:
完成所有工作;用管道输送到while IFS=: read -r user pw uid gid fullname homedir shell; do
循环;使用readarray -t
将线拉入shell数组中,您可以在其中直接使用它们;等
本文链接:https://www.f2er.com/3169523.html