3

我有一个 bash 脚本,我想在其中执行此操作

    (in pseudo)
    for each item in excludelist
        append to string: | grep -v $item

    for each file in directory 
    do
        stuff
    done

现在

   (in real code, the creation and concatenation of f works, the problem is not here I believe)
   for i in $EXCLUDE
   do
       echo $i
       f="$f | grep -v $i"
   done

   for d in `ls $AWSTATSCONF/awstats*conf $f`
   do
       echo $d
   done

输出

   ls: |: No such file or directory
   ls: grep: No such file or directory

任何和所有的帮助都非常感谢让这个工作。

问候,

阴影

4

5 回答 5

2

由于您使用的是 bash,因此您可以使用模式匹配来排除您的 EXCLUDE 列表:

pattern=$(awk ' BEGIN {OFS="|"; printf("!(")} 
                {$1=$1; printf("%s",$0)} 
                END {print ")"}
              ' <<< $EXCLUDE)
shopt -s extglob
for d in $pattern; do
  echo $d
done    
于 2012-05-07T13:36:24.680 回答
2

有很多方法可以处理它。

正确地,对解析ls. 它们的合理性取决于您是否必须处理所有可能的文件名(包含空格和换行符的文件名特别成问题),或者您是否有仅使用可移植文件名字符集的普通文件名(根据POSIX,是(拉丁)字母、数字、加.、、-_)。

假设您只需要处理可移植文件名,那么您可以获得您想要的效果:

for i in $EXCLUDE
do
    echo $i
    f="$f | grep -v $i"
done

for d in `eval ls $AWSTATSCONF/awstats*conf $f`
do
    echo $d
done

像这样使用eval会强制外壳将字符串$f中的管道视为外壳中的管道。 当心:eval是一个强大且因此很危险的工具。

如果要排除 20 个术语,则选择按顺序运行 20 个 grep 的机制使用大量进程。出于演示目的,它可能不会太严重,但如果您正在处理生产工作和数千个文件......不太好。

你可能想看看构建一个egrep(或grep -E)命令:

f="antidisestablishmentarianism"
for i in $EXCLUDE
do
    f="$f|$i"
done

ls $AWSTATSCONF/awstats*conf |
egrep -v "$f" |
while read d
do echo $d
done

我假设您没有任何名称包含“反反建制主义”的统计文件(是的,这是一个真实的词;不过,它在这里主要用作笑话)。

while read公式是编写for循环的另一种方式。小心子进程不能影响父 shell 的变量。也就是说,while循环由子 shell 处理,而不是主 shell,所以如果你依赖循环在主 shell 中设置变量,它将不起作用——你可以/应该回到for循环. 但是,您不再需要eval

for d in $(ls $AWSTATSCONF/awstat*conf | egrep -v "$f")
do
    echo $d
done

使用$(...)而不是反引号通常是一个好主意。

于 2012-05-07T14:06:27.537 回答
0

问题是它foo whatever whatever else作为 ls 命令的普通转义参数执行(当然 | 和 grep 在当前目录中找不到)。eval是将字符串作为 bash 命令执行的命令

您需要执行以下操作

for d in `eval "ls $AWSTATSCONF/awstats*conf $f"`
do
   echo $d
done

请记住,这会在安全方面打开一大堆蠕虫,请查看以下常见问题解答以了解更多信息和其他替代方案

于 2012-05-07T08:45:05.457 回答
0

不要使用for i in $(ls). 您应该使用通配符。

不要使用连接来构建一长串grep -v.

从哪里来$EXCLUDE?它应该是一个数组而不是一个字符串。

for d in "$AWSTATSCONF"/awstats*conf
do
    for e in "${exclude[@]}"
    do
        if [[ $d != $e ]]
        then
            echo "$d"
        fi
    done
done
于 2012-05-07T09:14:22.267 回答
-1

您需要将 * 输出附加grep$f

$f = "$f $(grep -v $i)"
于 2012-05-07T08:22:49.340 回答