我有一个作业,在一个脚本文件中运行一系列 (n)awk 命令。这个脚本文件的关键是过滤掉此处原始文本文件中的某些行和记录,称为学生:
Frank Smith Engineering Senior C
John Doe Marketing Junior B
Nancy Jones Engineering Junior A
Betty Anderson Nursing Sophomore B
Bob Johnson History Freshman B
James Smith Economics Senior A
我的脚本文件中有这些 awk 命令测试脚本.脚本。
{print $2, $1, $3, $4, $5}
/A$/ {print $1, $2}
/!A$/ {print $1, $2}
截至目前,当我跑步时nawk -f testscript.script students
对于输出的前几行我得到:
Smith Frank Engineering Senior C
Doe John Marketing Junior B
Jones Nancy Engineering Junior A
Nancy Jones
Anderson Betty Nursing Sophomore B
Johnson Bob History Freshman B
Smith James Economics Senior A
James Smith
如您所见,第二条命令与第一条命令融合在一起,而不是像所希望的那样分开。
这就引出了我的问题:如何分离 shell 脚本中的命令,以便每个新命令都有与其他命令独立的输出?
答案1
它运行完美,正如预期。
您的命令可以简单地重写为:
awk '{print $2, $1, $3, $4, $5}; /A$/ {print $1, $2}; /!A$/ {print $1, $2}' students
它由3个表达式组成awk
:
{print $2, $1, $3, $4, $5}
/A$/ {print $1, $2}
/!A$/ {print $1, $2}
所有 3 个表达式都将应用于所有记录。
第一个是相应地重新排列字段
如果记录以
A
(/A$/
) 结尾,则第二个匹配,如果是这样,则打印第一个和第二个字段如果记录以 结尾
!A
,则第三个匹配,如果是这样,则打印第一个和第二个由于前两条记录不满足表达式2的条件,因此按照表达式1打印字段。记录号4和5也是如此
只有记录 3 和 6 符合第二个表达式的条件,即以结束,
A
因此此条件的操作(即打印前两个字段)在执行表达式 1 之后立即执行,即打印重新排列的字段。因此,对记录 3 和 6 应用了两个操作。我想这就是让你绊倒的原因。没有任何记录符合表达式 3 的条件,即以 结尾
!A
,也许您想使用条件作为!/A$/
即不以 结尾的记录A
(并应用所需的操作)。
答案2
您可能更愿意编写一个foo.sh
包含三个 awk 命令的 shell 脚本(比如说),而不是包含三个块的单个 awk 脚本:
#!/bin/sh
awk '{print $2, $1, $3, $4, $5}' "$1"
awk '/A$/ {print $1, $2}' "$1"
awk '/!A$/ {print $1, $2}' "$1"
然后下面应该会给出期望的结果:
sh foo.sh students
(您也可以先执行chmod +x foo.sh
,然后运行./foo.sh students
。)
答案3
引起我注意的首先两个问题:
- 您可能想说
!/A$/
不是,/!A$/
因为我想您不想匹配以文字结尾的行,!A
但不以文字结尾的行A
- 我不知道这是由于您在此处发布示例的方式,还是您的初始数据集中存在这种情况,但有些行包含尾随空格。例如,尝试查看哪些行匹配
/B$/
以了解我的意思。幸运的是,没有以结尾的行A
有尾随空格,因此您的表达式/A$/
仍然有效,但它必须被视为脆弱的,因此$5=="A"
在任何情况下都应该是首选。
对于你的主要问题,如何“分离”每行的输出,我认为最简单的方法是使用文件重定向。即
{print $2, $1, $3, $4, $5 >"students-reorderd-columns"}
$5=="A"{print $1, $2 >"a-students"}
$5!="A"{print $1, $2 >"non-a-students"}
但是如果您确实需要将其发送到标准输出并希望避免使用cat students-reorderd-columns a-students non-a-students
临时文件,您可以研究sprint
并收集变量中的输出并将它们打印在一个END
块中(这对读者来说应该是一个很好的练习)。