【问题标题】:How to output awk result to file如何将awk结果输出到文件
【发布时间】:2011-01-08 17:55:33
【问题描述】:

我正在尝试将“awk”结果输出到脚本中的文件,但没有成功。 使用'>'不起作用,为什么?

for a in $(find $OUPUT_DIR/ -maxdepth 1 -mindepth 1 -type d -printf "%P\n")
do
    echo $a is a directory
    awk -F, '{ if ($10 == '"$a"') print $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a/CDR-${CDR_DATE}.csv
done 

【问题讨论】:

  • 奇怪的是> 不起作用。你能告诉我们你的代码吗?
  • for a in $(find $OUPUT_DIR/ -maxdepth 1 -mindepth 1 -type d -printf "%P\n") do echo $a is a directory awk -F, '{ if ( $10 == '"$a"') 打印 $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a/CDR-${CDR_DATE}.csv 完成
  • 以什么方式不起作用?你得到 any 输出了吗?文件是否正在创建但为空?等等……
  • 您的 CDRNOutput CSV 文件的格式是什么?
  • 您的代码未显示 CDR_DATE 正在设置。此外,您已经说过几次“不起作用”,但您还没有说出它正在在做什么。错误信息?空输出文件?输出文件放错地方了?文件中的错误输出?如果省略重定向,是否会在屏幕上打印正确的预期输出?

标签: linux bash scripting awk


【解决方案1】:

输出重定向通常是您正在使用的 shell 的一项功能,考虑到它的使用量,如果您在其中发现错误,我会非常惊讶 :-)

您确定不尝试使用 awk 本身而不是 shell 进行重定向吗?

当你这样做时会发生什么:

echo 'hello' | awk '{print}' >qq.tmp

更新:

如果这是您所述的代码,那是因为 $a 没有被您的 shell 脚本扩展,因为 awk 命令在单引号内。

for a in $(find $OUPUT_DIR/ -maxdepth 1 -mindepth 1 -type d -printf "%P\n")
do
    echo $a is a directory
    awk -F, '{ if ($10 == '"$a"') print $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a/CDR-${CDR_DATE}.csv
done

我倾向于使用-v 选项将特定值传递给awk,类似于(在您的情况下):

awk -F, -v a=$a '{ if ($10==a) print $0 }' ...

然后变量成为一流的awk 公民,而不必担心谁在进行扩展。


进一步更新:

我支持我最初的建议。选择的方法肯定有问题。

我的主目录中有一个名为 XpVm(以及其他)的目录,并且我创建了包含单行的文件 CDRNOutput_X.csv

1,2,3,4,5,6,7,8,9,XpVm,11

当我执行时:

for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, '{
        if ($10 == '"$a"') {
            print $0
        } else {
            print "NO";
        }
    }' ./CDRNOutput_X.csv
done

(我已经删除了以. 开头的目录,因为它们引起了另一个问题),我得到了这个输出:

workspace is a directory
NO
Documents is a directory
NO
XpVm is a directory
NO
Downloads is a directory
NO

这显然不是预期的。但是,当我按照我最初的建议将-v 选项用于awk 时,命令:

for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, -v a=$a '{
        if ($10 == a) {
            print $0
        } else {
            print "NO"
        }
    }' ./CDRNOutput_X.csv
done

(唯一的区别是对a 的更改),我得到:

workspace is a directory
NO
Documents is a directory
NO
XpVm is a directory
1,2,3,4,5,6,7,8,9,XpVm,11
Downloads is a directory
NO

这是正确的。


最终更新(希望如此):

我想我的问题已经解决了。我现在在另一台机器上(所以目录名称只是tmptmp2),当我运行原始脚本时:

for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, '{
        if ($10 == '"$a"') {
            print $0
        } else {
            print "NO";
        }
    }' ./CDRNOutput_X.csv
done

修改后的CDRNOutput_X.csv 包含tmp 而不是XpVm,我得到:

tmp is a directory
NO
tmp2 is a directory
NO

这是因为if 语句被awk 视为:

        if ($10 == tmp) {

(不带引号,因为引号实际上是 awk 字符串用于包围目录名称)。这将测试$10awk 变量tmp 的相等性,而不是实际的字符串"tmp"。您需要确保引号在 inside awk 脚本中,例如:

        if ($10 == "tmp") {

您可以使用以下脚本执行此操作(仅 if 行已更改):

#!/bin/bash
for a in $(find . -maxdepth 1 -mindepth 1 -type d -printf "%P\n" | grep -v '^\.')
do
    echo $a is a directory
    awk -F, '{
        if ($10 == "'"$a"'") {
            print $0
        } else {
            print "NO";
        }
    }' ./CDRNOutput_X.csv
done

请注意,双引号是重复的。我仍然在$a 周围立即保留双引号,以防有人犯下了创建带有空格的文件的令人发指的罪行:-)

运行该脚本会产生:

tmp is a directory
1,2,3,4,5,6,7,8,9,tmp,11
tmp2 is a directory
NO

这就是我认为你的目标。

所以,结果是,如果您不想使用 awk 变量,您可以将您的 awk 字符串更改为:

'{ if ($10 == '"$a"') print $0 }'

到:

'{ if ($10 == "'"$a"'") print $0 }'

它应该可以正常工作。

【讨论】:

  • @paxdiablo - 该语句结束单引号,然后用双引号将 $a 括起来,这样它就可以工作了。将 awk 更改为 echo 并尝试自己确认。
  • 其实awk也有重定向机制:awk '{print > "filename"}' 写入一个名为filename的文件。
  • 试过这个命令:awk -F, -va=$a '{ if ($10 == a) print $0 }' $OUPUT_DIR/CDRNOutput_${CDR_DATE}.csv > $OUPUT_DIR/$a /CDR-${CDR_DATE}.csv 仍然不起作用
  • @Jouni,该特定变体每次都会覆盖文件,这不太可能是我们想要的。 @RSam,好点(尽管我仍然更喜欢我的)。但现在测试成功了,我们需要来自 OP 的更多信息。
  • 我正在使用 -v (如之前的评论中所述),但仍然无法正常工作。我使用了 'sex -X' 所以我可以看到命令,命令是: awk -F, -va=512543 '{ if ($10 == a) print $0 }' /tmp/Camps/CDRNOutput_2010-01-01 .csv
【解决方案2】:

因为你有 find 命令将 -mindepth 和 maxdepth 设置为 1,你可以用 shell 来做

#!/bin/bash
CDR_DATE="somedate"
infile=CDRNOutput_${CDR_DATE}.csv
outfile=CDR-${CDR_DATE}.csv
OUPUT_DIR="/some/dir"
cd $OUPUT_DIR
for dir in */
do
    echo "${dir%/*} is a directory"
    dir=${dir%/*}
    while read -r a b c d e f g h i j k
    do
        case "$j" in
            $dir) echo $a $b $c $d $e $f $g $h $i $j $k >> $dir/$outfile;;
        esac
    done < $infile
done

【讨论】:

    猜你喜欢
    • 2015-05-07
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2023-03-19
    • 2011-01-28
    • 2015-01-12
    相关资源
    最近更新 更多