bash for loop不断添加变量顶部

循环将添加变量,而不是重写变量。我不知道为什么会这样。 如果有人可以帮助我,那么非常感谢您,我是bash的新手,我已经在这里呆了几个小时了……

for (( i=1; i<=4; i++ ))
do
    echo User:$(tail -n $i /etc/passwd | cut --delimiter=":" --fields="1")
    echo
    echo
done

输出变为

User:art101c40
User:art101c39 art101c40
User:art101c38 art101c39 art101c40
User:art101c37 art101c38 art101c39 art101c40

应该看起来像这样

User: art101c40
User: art101c39
User: art101c38
User: art101c37
dhtz_123 回答:bash for loop不断添加变量顶部

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替换cutwhile 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

大家都在问