根据单词将文件拆分为两个文件

根据单词将文件拆分为两个文件

male_nominee.txt编写 Shell 脚本,female_nominee.txt根据性别将以下文件拆分为两个文件 。如果文件 male_nominee.txtfemale_nominee.txt已存在,则追加内容。

female_nominee.txt显示和的内容male_nominee.txt

names.txt

23|Arjun|Male

24|Akshara|Female

17|Aman|Male

19|Simran|Female

我的代码:

while IFS= read -r line;
do
    if i=$(grep "Male" names.txt)
    then
        echo "$line" >> male_nominee.txt
    fi
    if j=$(grep "Female" names.txt)
    then
        echo "$line" >> female_nominee.txt
    fi
done < "names.txt"
ls
cat male_nominee.txt
cat female_nominee.txt

names.txt在我的输出中,我的两个文件中都有 的内容。有人可以帮我解决这个问题吗?

答案1

还有一些变化:

awk — 单遍

awk -F'|' '
   $3 == "Male"   { print >> "male_nominee.txt"   }
   $3 == "Female" { print >> "female_nominee.txt" }
          ' names.txt

如同jesse_b 的回答,但它只读取文件一次,并在 awk 脚本内执行 I/O 重定向。请注意,这些 awk 答案允许修改数据格式;例如,

年龄|姓名|性别|高度|重量|…

|但他们会忽略第二个和性别之间有空格的那一行。

巴什

#!/bin/bash
while read line
do
        if [[ $line =~ Male$ ]]
        then
                printf '%s\n' "$line" >> male_nominee.txt
        fi
        if [[ $line =~ Female$ ]]
        then
                printf '%s\n' "$line" >> female_nominee.txt
        fi
done < names.txt

我想这就是您想要做的 - 将每一行读入 shell 并测试性别是男性还是女性。

  • 一般来说,杰西是对的:您通常应该避免使用 while read。看为什么使用 shell 循环处理文本被认为是不好的做法?  但使用 shell 循环处理文本的缺点之一是人们经常在循环的每次迭代中调用外部实用程序,而本示例没有这样做。
  • 另外,如果你被人为指派去做某事完全在壳里, 那么你应该遵守作业规则。
  • 这对文件中的空格更加宽容,但不允许在 sex 之后有额外的数据。
  • 在 bash 中,=~将字符串与正则表达式进行比较。在正则表达式中,$表示结束,因此$line =~ Male$ 检查是否$line 以。。结束 Male。如果我们只说$line =~ Male(不带$),那么一个名叫沉睡魔咒的女人将被算作男人。
  • 如果您担心\数据中存在反斜杠 (),请使用read -r而不是仅使用read
  • 在这种情况下可能无关紧要(如果每一行都以数字开头),但通常printf比更安全echo

POSIX外壳

#!/bin/sh
while read line
do
        case "$line" in
            (*Male)
                printf '%s\n' "$line" >> male_nominee.txt
                ;;
            (*Female)
                printf '%s\n' "$line" >> female_nominee.txt
                ;;
        esac
done < names.txt
  • 这将比 bash 版本更便携。
  • case是根据 shell 中的模式测试字符串的传统方法。它使用文件名匹配(即 glob)模式而不是正则表达式。
  • 全局模式必须匹配,因此我们需要*在性别值之前放置 a 。如果我们检查Male(没有 *),它将仅匹配那些仅有的这个词Male (即没有年龄和名字)。另一方面,这意味着我们不需要在末尾放置任何标记。

答案2

“显示 Female_nominee.txt 和male_nominee.txt 的内容”要求有点不清楚,IMO 在脚本中没有位置,但我还是将其包含在内。您通常应该避免使用 while read 循环读取文件,并且由于这是一个分隔文件,因此可以使用 awk 轻松管理:

#!/usr/bin/env sh 

infile=./names.txt

awk -F\| '$3 == "Male"' "$infile" >> male_nominee.txt
awk -F\| '$3 == "Female"' "$infile" >> female_nominee.txt

cat male_nominee.txt female_nominee.txt

此外,您的脚本存在一些问题:

您的if语句是 grep fromnames.txt而不是,line因为该文件包含这两个条件Male,并且Female两个条件每次都会通过。

无需在每一行中分配给变量,该变量永远不会被使用。你可以这样做if echo "$line" | grep -q 'Male'; then

您不需要两个 if 语句,因为它将是 if/else

if echo "$line" | grep -q 'Male'; then
  echo "$line" >>male_nominee.txt
else
  echo "$line" >>female_nominee.txt
fi

答案3

你的问题是声明

if i=$(grep "Male" names.txt)

将要:

  1. 整体搜索“男”names.txt
  2. 返回输出(“所有包含 Male 的行”)并将其分配给变量i
  3. 如果分配成功(应该总是成功),执行 if 的内容

当您逐行阅读时,您可能只想检查该行。

您可以使用if echo "$line" | grep -q "Male"(或者,如果您想避免 -q,这不是由 POSIX 定义的,请将输出重定向到/dev/null

请注意,这将在整行中搜索“Male”,因此如果文件中包含名为“AMalek”的人,则可能会失败。

当您逐行阅读而不是阅读时,您可以使用IFS="|" read -r age name gender然后只是if [ $var = "value" ];

另一种选择是使用 grep,需要一个前导“|” (注意它是一个特殊字符)并且它结束该行。

请注意,在这种情况下,您可以用几个 grep 替换整个循环。

(女性的错误与男性的错误完全相同)

答案4

这是一个简单的解决方案,使用 grep 进行过滤并使用“>>”进行追加。

grep "Female$" names.txt >> female_nominee.txt
grep "Male$" names.txt >> male_nominee.txt

cat female_nominee.txt
cat male_nominee.txt

相关内容