male_nominee.txt
编写 Shell 脚本,female_nominee.txt
根据性别将以下文件拆分为两个文件 。如果文件male_nominee.txt
或female_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)
将要:
- 整体搜索“男”
names.txt
- 返回输出(“所有包含 Male 的行”)并将其分配给变量
i
- 如果分配成功(应该总是成功),执行 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