如何从 n 到 n 个元素

如何从 n 到 n 个元素
grep -i 'search' var/log/sample.log | less -S | awk '{print $1,$2,$3,$31,$32,$33,$34,$35,$36,$37}'

我只想打印从31到末尾或者从3134元素,而不想一一列出它们。

您能推荐一个for我可以整合的循环给我吗?

如果您能仅使用 提出解决方案,则可获得加分awk

请不要提出建议cut,因为这不是重点。

谢谢。

答案1

您可以尝试以下方法:

awk '{for (i = 31; i <= NF; i++)  printf "%s ",$i;printf "\n"}'

这将打印从 31 到末尾的所有字段如果您想要有特定的限制,请使用如下代码(例如到 34):

awk '{for (i = 31; i <= 34; i++)  printf "%s ",$i;printf "\n"}'

答案2

这将打印字段1-331-最后一行即可:

awk '
{
    for (i=1; i<=3; i++)
        printf "%s%s", $i, OFS
    for (i=31; i<=NF; i++)
        printf "%s%s", $i, OFS
    printf "%s", ORS
}'

笔记:

  • 我不使用明确的空格来分隔字段,而是使用OFS。的默认值OFS是一个空格。
  • 我不使用显式换行符来分隔记录,而是使用ORS。的默认值ORS是换行符。

使用此类标准awk变量是一种很好的做法。如果您需要非默认值,则无需更改代码(例如awk -v OFS=- …)。

上面的代码非常简单,但你可能会喜欢也可能不喜欢它关于OFSs 的“策略”:第一个for循环总是会生成 3 个OFSs,即使输入行为空;并且总是会至少有一个尾随OFS


以下变体避免了多余的OFSs:

awk '
{
    for (i=1; i<=3 && i<=NF; i++)
        printf "%s%s", (i==1)? "" : OFS, $i
    for (i=31; i<=NF; i++)
        printf "%s%s", OFS, $i
    printf "%s", ORS
}'

使用技巧:

  • i<=NF第一个循环中的附加条件for使得它不会打印OFS输入中不存在的字段。
  • 我们不是OFS在字段之后打印并试图抑制最后一个(尾随)字段,而是OFS在字段之前打印并抑制第一个打印的字段。重点是很容易分辨出哪个字段将作为输出中的第一个打印(即使可能会有所NF不同);但很难分辨出哪个字段将作为最后一个打印(如果可能会有所不同NF)。

另一方面,您的示例代码({print $1,$2,$3,$31,$32,$33,$34,$35,$36,$37})打印 10 个字段,并且确切地9秒,即使输入行为空。我不知道这是否是您需要的。打印的最后一个字段后OFS没有尾随。要实现类似的效果,请尝试以下操作:OFS

awk '
{
    for (i=1; i<=3; i++)
        printf "%s%s", (i==1)? "" : OFS, $i
    for (i=31; i<=NF || i<=37; i++)
        printf "%s%s", OFS, $i
    printf "%s", ORS
}'

如果输入中有 37 个或更少的字段,则将恰好有 9OFS个;这将表现得像您的代码。额外的字段(第 38 个及以后)将OFS在输出中生成更多 s 和字段。

答案3

all-awk(除了确定屏幕宽度,这在 awk 中无法实现)相当于:

grep -i 'search' var/log/sample.log | less -S | awk '{print $1,$2,$3,$31,$32,$33,$34,$35,$36,$37}'

与任何 awk 一起使用:

awk -v width="$(tput cols)" '
    { $0 = substr($0,1,width) }
    tolower($0) ~ /search/ {
        for (i=1; i<=3; i++) {
            printf "%s%s", $i, OFS
        }
        for (i=31; i<=37; i++) {
            printf "%s%s", $i, (i<37 ? OFS : ORS)
        }
    }
' var/log/sample.log

或者使用 GNU awk 进行 gensub() (未经测试,因为您没有提供任何输入/输出来测试):

awk -v width="$(tput cols)" '
    { $0 = substr($0,1,width) }
    tolower($0) ~ /search/ {
        print gensub(/\s*((\S+\s+){3})(\S+\s+){27}((\S+\s+){6}\S+).*/,"\\1\\4",1)
    }
' var/log/sample.log

相关内容