使用 bash 在特定列中提取具有特定值的行
extract rows with specific value in a specific column using 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" ' == 12' $f > /home/user/extra/$file/$filename;
done
但这会产生空文件,我不确定我做错了什么。将不胜感激。
你可以试试这个awk
awk -v file="/home/user/extra/$file/$filename" '==12 {print > file}' "$f"
请阅读 Correct Bash and shell script variable capitalization and https://mywiki.wooledge.org/Quotes to understand some of the issues in your script and copy/paste any shell script you write into https://www.shellcheck.net/ 直到掌握基本原理。
关于 But this produces empty files
- 当然,对于任何给定命令 cmd
和
for f in *; do
cmd "$f" > "out$f"
done
您正在为 shell 循环中的每个输入文件创建一个输出文件,因此如果任何输入文件与您的 awk 脚本中的 ==12
不匹配(cmd
在这种情况下)你仍然会得到一个输出文件,它只是空的。如果你不想这样,你可以这样做:
tmp=$(mktemp)
for f in *; do
cmd "$f" > "$tmp" &&
mv -- "$tmp" "out$f"
done
并写入 cmd
以 succ/fail 状态退出,就像 grep
在找到匹配项时所做的那样(在 awk 中微不足道),或者您可以检查 [=20 的大小=] 在 mv
:
之前
tmp=$(mktemp)
for f in *; do
cmd "$f" > "$tmp" &&
[[ -s "$tmp" ]] &&
mv -- "$tmp" "out$f"
done
不过,您不需要 shell 循环或其他命令,只需调用 awk 一次即可一次处理所有文件。在每个 Unix 机器上的任何 shell 中使用任何 awk 只做 this
awk -v file='random' -F'\t' '
FNR == 1 {
close(out)
f = FILENAME
sub(".*/","",f)
out = "/home/user/extra/" file "/" f
}
== 12 {
print > out
}
' /home/user/data/*.txt
如果您想要字符串而不是数字比较,以便 12.
与 12
不匹配,则执行 == "12"
而不是 == 12
。
在上面 file
是一个糟糕的变量名选择来保存 目录 的名称,但我把它放在一边以避免更改任何我没有更改的内容不得不。
我有 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" ' == 12' $f > /home/user/extra/$file/$filename;
done
但这会产生空文件,我不确定我做错了什么。将不胜感激。
你可以试试这个awk
awk -v file="/home/user/extra/$file/$filename" '==12 {print > file}' "$f"
请阅读 Correct Bash and shell script variable capitalization and https://mywiki.wooledge.org/Quotes to understand some of the issues in your script and copy/paste any shell script you write into https://www.shellcheck.net/ 直到掌握基本原理。
关于 But this produces empty files
- 当然,对于任何给定命令 cmd
和
for f in *; do
cmd "$f" > "out$f"
done
您正在为 shell 循环中的每个输入文件创建一个输出文件,因此如果任何输入文件与您的 awk 脚本中的 ==12
不匹配(cmd
在这种情况下)你仍然会得到一个输出文件,它只是空的。如果你不想这样,你可以这样做:
tmp=$(mktemp)
for f in *; do
cmd "$f" > "$tmp" &&
mv -- "$tmp" "out$f"
done
并写入 cmd
以 succ/fail 状态退出,就像 grep
在找到匹配项时所做的那样(在 awk 中微不足道),或者您可以检查 [=20 的大小=] 在 mv
:
tmp=$(mktemp)
for f in *; do
cmd "$f" > "$tmp" &&
[[ -s "$tmp" ]] &&
mv -- "$tmp" "out$f"
done
不过,您不需要 shell 循环或其他命令,只需调用 awk 一次即可一次处理所有文件。在每个 Unix 机器上的任何 shell 中使用任何 awk 只做 this
awk -v file='random' -F'\t' '
FNR == 1 {
close(out)
f = FILENAME
sub(".*/","",f)
out = "/home/user/extra/" file "/" f
}
== 12 {
print > out
}
' /home/user/data/*.txt
如果您想要字符串而不是数字比较,以便 12.
与 12
不匹配,则执行 == "12"
而不是 == 12
。
在上面 file
是一个糟糕的变量名选择来保存 目录 的名称,但我把它放在一边以避免更改任何我没有更改的内容不得不。