我试图从一系列很长的文件中收集一行。不幸的是,我需要从1600个不同目录中的同名文件中提取相同的行。目录结构是这样的。
目录jan10包含已执行的bash脚本和名为18-109的目录。目录18-109每个包含名为18A,18B,...,18H的目录。每个目录中都有文件" target.out"我们想要的信息来自。以下是我为访问此信息而编写的代码:
for i in $(cat ~/jan10/list.txt);
do
cd $i
cd *A
grep E-SUM-OVERALL target.out | cut -c 17-24 > ../overallenergy.out
cd ../*B
grep E-SUM-OVERALL target.out | cut -c 17-24 >> ../overallenergy.out
cd ../*C
grep E-SUM-OVERALL target.out | cut -c 17-24 >> ../overallenergy.out
cd ../*D
grep E-SUM-OVERALL target.out | cut -c 17-24 >> ../overallenergy.out
cd ../*E
grep E-SUM-OVERALL target.out | cut -c 17-24 >> ../overallenergy.out
cd ../*F
grep E-SUM-OVERALL target.out | cut -c 17-24 >> ../overallenergy.out
cd ../*G
grep E-SUM-OVERALL target.out | cut -c 17-24 >> ../overallenergy.out
cd ../*H
done
在此示例中,list.txt包含不同行上的数字18-109。 " list.txt"的一个例子。如下所示:
17
18
19
20
21
22
23
24
25
出乎意料的是,这段代码根本无法正常工作,它会返回错误:
./testscript.sh: line 8: cd: 18: No such file or directory
./testscript.sh: line 11: cd: *A: No such file or directory
它会为每个编号的目录和每个带字母的子目录返回此错误。有没有人对我做错了什么有任何见解?我会回答任何问题,如果不清楚,我会再次道歉。 grep命令本身确实有效,所以我认为这是" cd"之一的问题。命令,但我不确定。代码正在jan10目录中执行。
答案 0 :(得分:0)
现在我更了解你的要求(我的错),这是一个更加充实的解决方案。
prompt$ cat simpleGrepScript.sh
#!/bin/bash
if ${testMode:-true} ; then
echo "processing file $1 into outfile ${1%/*}/../overallenergy.out" 1>&2
else
[[ -f "$1" ]] && grep 'E-SUM-OVERALL' "$1" > ${1%/*}/../overallenergy.out || echo "no file "$1" found" 1>&2
fi
运行
prompt$ find /starting/path -name target.out | xargs /path/to/simpleGrepScript.sh
如果testMode的输出
"processing file $1 into outfile ${1%/*}/../overallenergy.out"
看起来没问题,然后更改为${testMode:-false}
。
如果它看起来不正确,请将mininum错误示例发布为评论,然后我会查看是否可以修复它。
如果您的路径名中有空格,我们必须回过头来为find
和xargs
添加更多选项。
IHTH。
答案 1 :(得分:0)
for Dir in $(cat ~/jan10/list.txt)
do
find "$Dir" -type f -name target.out |
while read File
do
grep E-SUM-OVERALL "$File" > "${File%/*/target.out}"/overallenergy.out
done
done
答案 2 :(得分:0)
定义一个shell函数,对于给定目录,在stdout
上找到所有基础目标和每个目标输出,这是一个合适的命令。
% gen_greps () {
find $1 -name target.out | while read fname ; do
printf "grep E-SUM-OVERALL $fname | "
printf "cut -c 17-24 > "
printf "$(dirname $fname)/overallenergy.out\n"
done
}
%
干涸
% gen_greps jan10
...
grep E-SUM-OVERALL jan10/29/29H/target.out | cut -c 17-24 > jan10/29/29H/overallenergy.out
...
%
如果我们看到的是我们想要的,请将命令传递给shell执行
% gen_greps jan10 | sh
%
全部(?)
答案 3 :(得分:0)
请勿以这种方式使用for
。为了执行for
,它必须首先处理cat
命令,如果文件名中有空格,for
将失败。另外,在执行for
时,很可能会重载命令行。
而是使用while read
循环,它更有效,更容忍文件名问题:
while read dir
do
....
done < ~/jan10/list.txt
在cd
命令中使用glob模式也非常危险,因为多个文件可能匹配该模式,这可能导致cd
失败。
此外,如果您发现自己使用了一系列grep
,cut
,sed
命令,通常可以使用单个awk
命令替换它。
如果您需要的所有文件都被称为target.out
并且没有其他名为target.out
的文件要跳过,则可以使用find
查找各种文件而不更改每个目录:
请注意整个程序的简短程度和简单程度:
while read dir
do
find $dir -name "target.out" -type f \
-exec awk '/E-SUM-OVERALL/ {print substr $0, 17, 8}' {}\;
done < ~/jan10/list.txt > overallenergy.out
我没有任何数据,所以实际测试这个很难。我可以简单地使用awk
中的字段而不是substr
。或者我的substr
命令可能已关闭。