bash - 使用 bash 在特定列中提取具有特定值的行
问题描述
我有 1000 个文本文件,每个文件都以制表符分隔,格式如下
John 32 NY 12 USA
Peter 78. CA. 8. USA
Stef. 67. CA. 12. USA
我想提取所有第四列正好是 12 的行。这就是我所做的:
file='random'
FILES=/home/user/data/*.txt
for f in $FILES;
do
echo $f
filename=$(basename $f)
awk -F"\t" '$4 == 12' $f > /home/user/extra/$file/$filename;
done
但这会产生空文件,我不确定我在这里做错了什么。见解将不胜感激。
解决方案
请阅读正确的 Bash 和 shell 脚本变量大写和https://mywiki.wooledge.org/Quotes以了解脚本中的一些问题,并将您编写的任何 shell 脚本复制/粘贴到https://www.shellcheck.net/直到你把基本面弄下来。
关于But this produces empty files
- 当然,对于任何给出的cmd
命令
for f in *; do
cmd "$f" > "out$f"
done
$4==12
您正在为 shell 循环中的每个输入文件创建一个输出文件,因此如果任何输入文件在您的 awk 脚本中不匹配(cmd
在这种情况下),您仍然会得到一个输出文件,它只是空的。如果你不希望你可以这样做:
tmp=$(mktemp)
for f in *; do
cmd "$f" > "$tmp" &&
mv -- "$tmp" "out$f"
done
并写入cmd
以成功/失败状态退出,就像grep
找到匹配项时一样(在 awk 中微不足道),或者您可以检查"$tmp"
之前的大小mv
:
tmp=$(mktemp)
for f in *; do
cmd "$f" > "$tmp" &&
[[ -s "$tmp" ]] &&
mv -- "$tmp" "out$f"
done
但是,您不需要 shell 循环或其他命令,只需 1 次调用 awk 即可一次处理所有文件。在每个 Unix 机器上的任何 shell 中使用任何 awk只做这个
awk -v file='random' -F'\t' '
FNR == 1 {
close(out)
f = FILENAME
sub(".*/","",f)
out = "/home/user/extra/" file "/" f
}
$4 == 12 {
print > out
}
' /home/user/data/*.txt
如果你想要一个字符串而不是数字比较,那么它12.
不匹配,12
然后做$4 == "12"
而不是$4 == 12
.
在上面file
是一个糟糕的变量名选择来保存一个目录的名字,但我把它放在一边以避免改变我不需要做的任何事情。
推荐阅读
- ibm-doors - 如何识别多次使用的工件
- ios - 可以将 ios 应用程序默认为特定背景亮度吗?
- python - 词袋方法将消息拆分为单个词
- security - 保护来自同源服务器的 HTML 内容
- css - 需要使用 tachyons 覆盖默认类
- excel - 导出到 excel 时在其他列之前插入额外列
- c# - 如何将长文本分成字节c#
- kubernetes - K8s 集群删除不会从 GCE 上的托管区域中删除 DNS 条目
- reactjs - React 组件使用的 Jest/Enzyme/Reactjs 测试函数
- c# - 检测用于 HttpClient POST 或 GET 调用的 TLS 版本