【问题标题】:Why does my "echo" only display 1 word? (Linux-Bash)为什么我的“回声”只显示 1 个字? (Linux-Bash)
【发布时间】:2020-10-18 03:08:13
【问题描述】:

我有一个username.txt,其中显示了用户名和组,用“,”分隔。我正在尝试仅将“访问者”组中的用户名复制到新的 txt。

我的用户名.txt:

mark,staff
jason,visitor
jack,visitor
orlando,visitor

这是我当前的 bash 脚本:

#!/bin/bash

username=username.txt

while IFS=, read username1 group1; do
 if [ $group1 = "visitor" ]; then
   echo $username1 > reportvisitors.txt
 fi
done < $username

我的报告访问者.txt

预期输出:

jason
jack
orlando

实际输出:

jack

【问题讨论】:

  • 查看上一个问题的答案。
  • 实际上,我的输出显示了 orlando,这是有道理的,因为它是您输入文件中的最后一个条目。
  • 有什么理由不使用 awk:awk -F, '$2=="visitor"{print $1 &gt; "reportvisitors.txt"}' "$username"?
  • 如果您想每次运行覆盖一次,请将&gt; reportvisitors.txt 放在done 之后。这样你仍然会截断文件,但你会在每个循环中截断一次,而不是每个 echo 一次。
  • 顺便说一句,这里有很多错误(在撰写本文时,在所有建议的答案中)与错误引用有关——尝试测试当访问者的用户名为 @ 时会发生什么987654330@。通过shellcheck.net 运行代码总是一个好主意。

标签: linux bash


【解决方案1】:

将 io 重定向运算符移动到循环的末尾。

#!/bin/bash

username=username.txt

while IFS=, read username1 group1; do
 if [ "$group1" = "visitor" ]; then
   echo "$username1"
 fi
done < "$username" > reportvisitors.txt

【讨论】:

  • 只需将&gt;reportvisitors.txt 移动到done 就足以使每次运行脚本时从头开始重写文件。您不需要rm切换到&gt;&gt;
  • 好多了;仍然存在的错误是仍然存在于 OP 代码中的错误。 (我仍然建议修复它们——引用 "$group1""$username"` 和 "$username")。
  • 您可以将 io 重定向运算符替换为 tee 实用程序的管道;这样您就可以在运行时看到输出,而不必等待脚本完成然后执行 cat。
【解决方案2】:

首先创建一个临时文件来打印结果。您可以使用 mktemp 实用程序来做到这一点。然后,如果没有发生错误,将该文件移至reportvisitors.txt。使用&gt;&gt; 而不是&gt; 追加到临时文件:

#!/bin/bash

username=username.txt
tmpfile=$(mktemp)

while IFS=, read username1 group1; do
    if [ $group1 = "visitor" ]; then
        echo $username1 >> "$tmpfile"
    fi
done < $username

mv "$tmpfile" reportvisitors.txt

这避免了即使脚本因错误而失败,您也会丢失 reportvisitors.txt 以前的内容的问题。

理想情况下,您的脚本应该具有错误处理功能,并在出现错误时删除临时文件。

【讨论】:

  • 为什么要重新打开tmpfile,每次想echo输出一行呢?如果你只打开一次,那么你也不需要从&gt;切换到&gt;&gt;。 (例如,将exec &gt;"$tmpfile" 放在tmpfile=$(mktemp) 之后,然后脚本中的每个echo 将默认附加到该已打开的文件句柄)。
【解决方案3】:

您使用的是&gt; 而不是&gt;&gt;,它会在每次循环迭代期间覆盖该文件中当前的数据。要将文本附加到文件中,您需要改用 &gt;&gt;。只需像这样修改您的脚本:

#!/bin/bash
username=username.txt

while IFS=, read username1 group1; do
echo $username1 $group1
 if [[ $group1 == "visitor" ]]; then
   echo $username1 >> reportvisitors.txt
 fi
done < $username

如果您使用此脚本的唯一目的是收集访问者,您可以在 awk 单行中实现相同的结果,如下所示:

awk -F, '{if($2 == "visitor")print $1}' username.txt > reportvisitors.txt

【讨论】:

  • OP 不希望脚本的多次运行导致文件具有一组以上的输出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 2016-09-12
相关资源
最近更新 更多