如何使用 AWK 在每个单元格中反向打印字符串的字符?

How can I reverse print the characters of a string in each cell using AWK?

Beth    45  4.00    0   0   .072
Danny   33  3.75    ^0  0   .089

以上是我要操作的文件

我想写一个 AWK 脚本,可以在每个单元格中反向打印字符串的字符。

代码如下:

BEGIN { OFS = "\t\t" } 
function reverse_print(str)
{
    s = ""; 
    N = length(str);
    for (i = 1; i <= N; i++)
        a[i] = substr(str, i, 1); 
    for (i = N; i >= 1; i--)
        s = s  a[i];
    return s;
}

{
    for (i = 1; i <= NF; i++)
        $i = reverse_print($i) ; 
    print;
}

END {}

但是,它不起作用。程序不知何故死了。

我发现如果我不使用循环并像下面这样一个一个地处理每个字段,

BEGIN { OFS = "\t\t" }
function reverse_print(str)
{
    s = "";
    N = length(str);
    for (i = 1; i <= N; i++)
        a[i] = substr(str, i, 1);
    for (i = N; i >= 1; i--)
        s = s  a[i];
    return s;
}

{
     = reverse_print() ; 
     = reverse_print() ; 
     = reverse_print() ; 
     = reverse_print() ; 
     = reverse_print() ; 
     = reverse_print() ; 
    print;
}

END {}

它可以很好地工作。

这是我想要的输出:

hteB        54      00.4        0       0       270.
ynnaD       33      57.3        0^      0       980.

我想了想还是想不通我循环哪里做错了

谁能告诉我为什么?

能否请您尝试以下操作。(此程序仅在 GNU awk 上测试,并且根据 Ed 先生的评论,这也是 POSIX awk 的未定义行为)

awk '
BEGIN{
  OFS="\t\t"
}
{
  for(i=1;i<=NF;i++){
    num=split($i,array,"")
    for(j=num;j>0;j--){
      val=(j<num?val:"") array[j]
    }
    printf "%s%s",val,(i<NF?OFS:ORS)}
    val=""
}'  Input_file

您在函数内外使用了相同的变量 i。在任一位置使用不同的变量或将函数定义更改为 reverse_print(str, i) 以使函数内使用的 i 成为该函数的局部变量,而不是在调用代码中使用相同的全局变量。

您还应该将 s 和 N 函数设为本地:

function reverse_print(str,     i, s, N)

但实际上代码应该写成:

$ cat tst.awk
BEGIN { OFS = "\t\t" }
function reverse_print(fwd,     rev, i, n)
{
    n = length(fwd)
    for (i = n; i >= 1; i--)
        rev = rev substr(fwd, i, 1);
    return rev
}

{
    for (i = 1; i <= NF; i++)
        $i = reverse_print($i)
    print
}

$ awk -f tst.awk file
hteB            54              00.4            0               0               270.
ynnaD           33              57.3            0^              0               980.

有一个rev command in Linuxrev - reverse lines characterwise

您可以通过使用 awk 内置函数 system 调用 rev 来反转字符串,例如:

#reverse-fields.awk
{
  for (i = 1; i <= NF; i = i + 1) {
    # command line
    cmd = "echo '" $i "' | rev"

    # read output into revfield
    cmd | getline revfield

    # remove leading new line
    a = gensub(/^[\n\r]+/, "", "1", revfield)

    # print reversed field
    printf("%s", a)

    # print tab
    if (i != NF) printf("\t")

    # close command
    close(cmd)
  }
  # print new line
  print ""
}
$ awk -f reverse-fields.awk emp.data
0    00.4    hteB
0    57.3     naD
01    00.4   yhtaK
02    00.5    kraM
22    05.5    yraM
81    52.4   eisuS