Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 表格式的Awk解决方案_Arrays_Bash_Shell_Unix_Awk - Fatal编程技术网

Arrays 表格式的Awk解决方案

Arrays 表格式的Awk解决方案,arrays,bash,shell,unix,awk,Arrays,Bash,Shell,Unix,Awk,有一个表格的格式如下。是否可以使用AWK脚本对表进行格式化,以排除只包含数字1的列 ST L1 L2 L3 L4 L5 ST2 1 1 1 1 1 ST2 1 0 1 0 1 ST3 1 0 1 0 1 ST3 0 0 1 1 1 ST4 1 0 1 0 1 ST5 1 0 1 0 1 ST6 1 0 1 0 1 ST7 0 0 1 1 1 ST8 0 0 1 0 1 ST9 1 0 1 0 1 输出应如下所示: ST L1 L2 L4 ST2 1 1 1 ST2 1 0 0 ST3 1 0

有一个表格的格式如下。是否可以使用AWK脚本对表进行格式化,以排除只包含数字1的列

ST L1 L2 L3 L4 L5
ST2 1 1 1 1 1
ST2 1 0 1 0 1
ST3 1 0 1 0 1
ST3 0 0 1 1 1
ST4 1 0 1 0 1
ST5 1 0 1 0 1
ST6 1 0 1 0 1
ST7 0 0 1 1 1
ST8 0 0 1 0 1
ST9 1 0 1 0 1
输出应如下所示:

ST L1 L2 L4
ST2 1 1 1
ST2 1 0 0
ST3 1 0 0
ST3 0 0 1
ST4 1 0 0
ST5 1 0 0
ST6 1 0 0
ST7 0 0 1
ST8 0 0 0
ST9 1 0 0

我可以理解一个列应该如何打印的逻辑,就像在结束块中的NR值一样,如果该值等于每次找到1时应该递增的变量,对于给定的列(除了标题NR==1和列$1),打印该列。我的问题在于实际上试图打印结束块中的列,因为我正在尝试使用数组,而我仍在学习AWK和数组。我相信有一些聪明的方法可以做到这一点,即使不使用数组,也不需要简单地改变AWK查看数据的方式

这应该可以做到:

    {
        # store current line
        line[FNR] = $0

        if (FNR > 1) # skip header
        {
            # select columns
            for (i = 1 ; i <= NF ; i++)
            {
                if ($i != 1) selected[i] = 1
            }
        }
    }

END {
        for (li = 1 ; li <= FNR ; li++)
        {
            # parse current line
            $0 = line[li]

            # pick selected fields
            for (i = j = 1 ; i <= NF ; i++)
            {
                if (selected[i]) $(j++) = $i
            }

            # trim record to selection
            NF = j-1
            print
        }
    }
埃德·莫顿发言后:

把l改成不那么模棱两可的东西 printf确实是一个语句,但添加括号也不会有什么坏处,或者会有什么坏处? 同意打印优于打印F\n 分号是可选的,但不会造成伤害。我觉得更舒服的东西看起来像C NR是一个没有被注意到的打字错误,因为它纯粹靠运气产生了预期的输出。我是说NF。 更改了逻辑,以便不再添加尾随空格,并且不再使用printf 在第二批评论之后:

更改了输出记录的生成,以避免使用无关的分隔符。
非常感谢你的校对。自从我上一次做一些严肃的hawk编程以来已经将近15年了,令人遗憾的是,锈迹已经开始了。

这应该可以解决问题:

    {
        # store current line
        line[FNR] = $0

        if (FNR > 1) # skip header
        {
            # select columns
            for (i = 1 ; i <= NF ; i++)
            {
                if ($i != 1) selected[i] = 1
            }
        }
    }

END {
        for (li = 1 ; li <= FNR ; li++)
        {
            # parse current line
            $0 = line[li]

            # pick selected fields
            for (i = j = 1 ; i <= NF ; i++)
            {
                if (selected[i]) $(j++) = $i
            }

            # trim record to selection
            NF = j-1
            print
        }
    }
awk '
NR==FNR {
    if (NR > 1) {
        for (i=1;i<=NF;i++) {
            if ($i != 1) {
                nonOnes[i]
            }
        }
    }
    next
}
{
    ofs=""
    for (i=1;i<=NF;i++) {
        if (i in nonOnes) {
            printf "%s%s", ofs, $i
            ofs=OFS
        }
    }
    print ""
}
' file file
ST L1 L2 L4
ST2 1 1 1
ST2 1 0 0
ST3 1 0 0
ST3 0 0 1
ST4 1 0 0
ST5 1 0 0
ST6 1 0 0
ST7 0 0 1
ST8 0 0 0
ST9 1 0 0
埃德·莫顿发言后:

把l改成不那么模棱两可的东西 printf确实是一个语句,但添加括号也不会有什么坏处,或者会有什么坏处? 同意打印优于打印F\n 分号是可选的,但不会造成伤害。我觉得更舒服的东西看起来像C NR是一个没有被注意到的打字错误,因为它纯粹靠运气产生了预期的输出。我是说NF。 更改了逻辑,以便不再添加尾随空格,并且不再使用printf 在第二批评论之后:

更改了输出记录的生成,以避免使用无关的分隔符。
非常感谢你的校对。自从我上次做一些严肃的hawk编程以来,已经将近15年了,令人遗憾的是,锈迹已经开始了。

千万不要使用字母l el作为变量,因为它看起来太像数字1了。printf是一个内置的,不是一个函数,所以paren并没有像它看起来那样做。打印是打印ORS的正常方式,因此无需硬编码。伪尾随分号是不可取的。FNR有时和NR有时的使用令人困惑。printf%s将向每个输出行添加尾随空白字符。您在上一个打印块中使用的是NR而不是NF。您可以在任何表达式周围添加paren,这与C中的returnfoo和sizeofbar相同,并且它不应该导致破坏,它只是让阅读您的代码的人想知道这样做的目的是什么。与添加不必要的内容相同;在陈述的结尾。我希望您的新解决方案会失败,因为每次遇到要跳过的$I时,您都会重新编译$0,因此字段编号的值在之后与您最初在中读取的值不同。或者它可能只是在字段之间留下额外的空白。我同意你对样式的评论。我使用C/C++的时间比使用awk的时间多得多,所以我只是简单地继承了这些习惯。但是,我不认为将$I设置为将重新编译$0$如果为$0分配新值或添加字段,则将重新编译0,而不是更改现有字段的值。医生是这么说的,我的经验告诉我至少使用gawk是这样的。将$i设置为可能确实会在输出字段之间留下几个空格,但OP并没有明确要求结果在每列之间只有一个分隔符,因此我似乎可以接受。将$i设置为任何值都会导致重新编译$0,请尝试echo a b c | awk-v of s=',“{$2=;print}”,但它看起来仍然会留下一个空字段,而不是在它的两边折叠FSs,即使这是对该记录的初始读取行为,所以是的,它只是字段之间的额外空格,在本例中是在最后一行的末尾。通常这是不受欢迎的,但我想你是对的$0确实是从$i记录合成的,但我的意思是,NF不会将设置$i更改为不销毁$i,除非您在之后执行类似$0=$0的操作以强制重新解析记录。不过,关于生产线末端的分离器的观点很好。这最终说服了我更改代码:。谢谢你的耐心和帮助,我向你对awk的掌握致敬。永远不要用字母l el作为变量,因为它看起来太像数字1了。printf是一个内置的,不是一个函数,所以paren并没有像它看起来那样做。打印是打印ORS的正常方式,因此不需要硬编码
awk '
NR==FNR {
    if (NR > 1) {
        for (i=1;i<=NF;i++) {
            if ($i != 1) {
                nonOnes[i]
            }
        }
    }
    next
}
{
    ofs=""
    for (i=1;i<=NF;i++) {
        if (i in nonOnes) {
            printf "%s%s", ofs, $i
            ofs=OFS
        }
    }
    print ""
}
' file file
ST L1 L2 L4
ST2 1 1 1
ST2 1 0 0
ST3 1 0 0
ST3 0 0 1
ST4 1 0 0
ST5 1 0 0
ST6 1 0 0
ST7 0 0 1
ST8 0 0 0
ST9 1 0 0

信息技术伪尾随分号是不可取的。FNR有时和NR有时的使用令人困惑。printf%s将向每个输出行添加尾随空白字符。您在上一个打印块中使用的是NR而不是NF。您可以在任何表达式周围添加paren,这与C中的returnfoo和sizeofbar相同,并且它不应该导致破坏,它只是让阅读您的代码的人想知道这样做的目的是什么。与添加不必要的内容相同;在陈述的结尾。我希望您的新解决方案会失败,因为每次遇到要跳过的$I时,您都会重新编译$0,因此字段编号的值在之后与您最初在中读取的值不同。或者它可能只是在字段之间留下额外的空白。我同意你对样式的评论。我使用C/C++的时间比使用awk的时间多得多,所以我只是简单地继承了这些习惯。但是,我不认为将$I设置为将重新编译$0$如果为$0分配新值或添加字段,则将重新编译0,而不是更改现有字段的值。医生是这么说的,我的经验告诉我至少使用gawk是这样的。将$i设置为可能确实会在输出字段之间留下几个空格,但OP并没有明确要求结果在每列之间只有一个分隔符,因此我似乎可以接受。将$i设置为任何值都会导致重新编译$0,请尝试echo a b c | awk-v of s=',“{$2=;print}”,但它看起来仍然会留下一个空字段,而不是在它的两边折叠FSs,即使这是对该记录的初始读取行为,所以是的,它只是字段之间的额外空格,在本例中是在最后一行的末尾。通常这是不受欢迎的,但我想你是对的$0确实是从$i记录合成的,但我的意思是,NF不会将设置$i更改为不销毁$i,除非您在之后执行类似$0=$0的操作以强制重新解析记录。不过,关于生产线末端的分离器的观点很好。这最终说服了我更改代码:。谢谢你们的耐心和帮助,我向你们对awk的掌握致敬。谢谢你们的回答,工作很好!现在我只想把我的头绕在代码上;谢谢你们的回答,工作很好!现在我只想把我的头绕在代码上;Hi-Ed-如何编写此代码来处理一个文件而不是多个文件?或者它依赖于有多个文件才能工作?它只在一个文件上工作。只需将相同的文件名传递两次。第一次解析文件时,它会找出哪些列不是所有的列,接下来它会打印不是所有的列。如果您不想将相同的文件名传递给脚本两次,请参阅我在文章底部所做的编辑,以添加一个与文件名arg.Hi-Ed重复的开始部分-如何编写此代码以仅处理一个文件而不是多个文件?或者它依赖于有多个文件才能工作?它只在一个文件上工作。只需将相同的文件名传递两次。第一次解析文件时,它会找出哪些列不是所有的列,接下来它会打印不是所有的列。如果您不想将相同的文件名传递给脚本两次,请参阅我在文章底部所做的编辑,以添加一个与文件名arg重复的开始部分。