我有一个充满 .tsv 文件的目录,我想对每个文件运行 grep 命令以提取一组特定的文本行,然后将其保存到具有相似文件名的关联文本文件中。例如,如果我只 grep 一个文件,我的 grep 命令如下所示:
grep -h 8-K 2008-QTR1.tsv > 2008Q1.txt
但我有一个 tsv 文件列表,如下所示:
2008-QTR1.tsv
2008-QTR2.tsv
2008-QTR3.tsv
2008-QTR4.tsv
2009-QTR1.tsv
2009-QTR2.tsv
2009-QTR3.tsv
...
在 grep 后,它们需要存储为:
2008Q1.txt
2008Q2.txt
2008Q3.txt
2008Q4.txt
2009Q1.txt
2009Q2.txt
2009Q3.txt
有什么想法吗?
答案1
在ksh93/bash/zsh中,通过简单的for
循环和参数扩展:
for f in *-QTR*.tsv
do
grep 8-K < "$f" > "${f:0:4}"Q"${f:8:1}".txt
done
这grep
一次运行一个文件(其中文件列表是根据通配符模式生成的,该模式要求文件名中存在“-QTR”以及文件名结尾的“.tsv”),将输出重定向到基于以下内容精心构建的文件名:
- 文件名的前四个字符——年份
- 这封信
Q
- 文件名的第 9 个字符——季度
答案2
强制性的 POSIXsh
变体:
#! /bin/sh -
ret=0
for file in [[:digit:]][[:digit:]][[:digit:]][[:digit:]]-QTR[1234].tsv; do
base=${file%.tsv}
grep 8-K < "$file" > "${base%%-*}Q${base##*-QTR}".txt || ret=$?
done
exit "$ret"
答案3
另外一个选择
for f in 200{8..9}-QTR{1..4}.tsv; do
grep "pattern" $f > $(sed "s/[-RTtsv]*//g" <<< $f)txt;
done
演练:设置一个扩展来创建文件名列表
200{8..9}-QTR{1..4}.tsv
扩展到
2008-QTR1.tsv 2008-QTR2.tsv 2008-QTR3.tsv 2008-QTR4.tsv 2009-QTR1.tsv 2009-QTR2.tsv 2009-QTR3.tsv 2009-QTR4.tsv
迄今为止每年和每个季度要做的事情是
20{08..19}-QTR{1..4}.tsv
遍历列表for..do..done
,从文件中提取您要查找的模式
grep "pattern" $f
并重定向到通过删除不需要的字符sed
并添加txt
后缀形成的新文件名
$(sed "s/[-RTtsv]*//g" <<< $f)txt
或者
$(sed "s/[-RT]*//g" <<< ${f%%.*}.txt)
答案4
如果想避免显式循环,有以下解决方案。也许有人能够改进它。它看起来像这样。
ls -1 *.tsv | xargs -n1 -I'{}' bash -c 'f="{}";grep 8-K $f > ${f//[^0-9Q]/}.txt'
- LS仅列出您要处理的文件
- 参数逐个处理这些文件中的每一个(-n1)
- A巴什启动 shell 以便能够处理字符串(参见第 5 点)
- 将文件名设置为变量$f
- ${f//[^0-9Q]/}删除 .txt 文件名中不需要的所有字符(因此这是特定于您的示例的)
优点: - 简单的一个衬垫
缺点: - 为每个处理的文件启动一个 bash 进程
也许有一个不使用 bash 的类似解决方案,但我不知道(例如, eval 不应该在这种情况下工作)