执行简单grep脚本时出现意外错误

时间:2014-11-20 15:59:13

标签: bash grep cd

我试图从一系列很长的文件中收集一行。不幸的是,我需要从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目录中执行。

4 个答案:

答案 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错误示例发布为评论,然后我会查看是否可以修复它。

如果您的路径名中有空格,我们必须回过头来为findxargs添加更多选项。

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失败。

此外,如果您发现自己使用了一系列grepcutsed命令,通常可以使用单个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命令可能已关闭。