shell 将列位置作为输入传递给AWK命令

9w11ddsr  于 7个月前  发布在  Shell
关注(0)|答案(3)|浏览(53)

脚本将把csv文件头位置A、C、B、D转换为A、B、C、D,输出变量VAR_INP将在awk中用于打印和创建新的csv文件。

VAR_INP="TMP1=$1 ; TMP2=$2 ; TMP3=$3 ; TMP4=$4 ; $1=TMP1 ;$3=TMP2 ;$2=TMP3 ;$4=TMP4 ;"

我需要在awk中使用这个VAR_INP作为输入命令。

echo "A,C,B,D" > input.csv

awk 'BEGIN { FS=OFS","}
{
$VAR_INP 
print
}' input.csv

预期输出

A,B,C,D

我没有得到预期的结果。它按原样打印输入。
只有当我展开VAR_INP并手动运行时,它才起作用
请告知。

laik7k3q

laik7k3q1#

在下面的命令输出中,前缀为-|。有几个问题:

  1. shell不会在单引号之间展开参数,而是在双引号之间展开参数。因此,要分配shell变量VAR_INP,您应该使用单引号,而不是双引号。否则$...会被shell展开,你的变量不再包含你想要的内容。演示:
VAR_INP="TMP1=$1 ; $1=TMP1"
echo "$VAR_INP"
-| TMP1= ; =TMP1
VAR_INP='TMP1=$1 ; $1=TMP1'
echo "$VAR_INP"
-| TMP1=$1 ; $1=TMP1

1.要将shell变量嵌入到awk脚本中,不能使用单引号,因为单引号会阻止扩展。您可以对awk脚本使用双引号,这样$VAR_INPawk运行之前由shell展开,但这将非常烦人,因为您必须转义所有其他$。使用awk-v选项来分配一个awk变量,并在awk脚本中仅使用其名称引用其值(无$):

VAR_INP='TMP1=$1 ; $2=TMP1'
awk -v VAR_INP="$VAR_INP" '
  BEGIN {print VAR_INP}
  {VAR_INP; print}' <<< "a should-become-a"
-| TMP1=$1 ; $2=TMP1
-| a should-become-a

1.正如你在前面的例子中看到的,你不能像这样在变量中嵌入awk代码,awk没有basheval的等价物,你不能要求awk像执行awk代码一样执行VAR_INP变量中的字符串。最接近的可能是system函数,但是从awk调用awk对于解决您的问题来说是无用的复杂。
相反,您可以传递一个带有数字列表的变量,这些数字表示输出中输入字段编号的有序列表。
下面的例子应该可以与任何POSIX awk一起使用,它已经在GNU awk和macOS附带的awk上进行了测试:

awk -F, -v OFS=, -v order='1,3,2,4' '
  BEGIN {n=split(order,a)}
  {for(i=1;i<=n;i++) printf("%s%s", $(a[i]), i<n?OFS:ORS)}
' <<< "A,C,B,D"
-| A,B,C,D

将输入和输出字段分隔符降为,。将输出顺序作为变量order传递。在输入字段分隔符上的BEGIN split order中,将结果存储在数组a中,并将元素数存储在n中。然后对于每个记录,从i=1循环到i=n并打印字段号a[i],如果是i<n,则输出字段分隔符(OFS),否则输出记录分隔符(ORS)。
如果您有许多列,但只想更改其中的几个,则只列出更改可能更容易。下面的from是要更改的字段列表,to是相应的字段编号列表。这里,输出场2、3、12和17分别被输入场17、2、3和12代替。其余46个字段保持不变。

awk -F, -v OFS=, -v from='2,3,12,17' -v to="17,2,3,12" '
  BEGIN {split(from,a); split(to,b); for(i in a) c[a[i]]=b[i]}
  {for(i=1;i<=NF;i++) printf("%s%s", (i in c)?$(c[i]):$i, i<NF?OFS:ORS)}
' < <(printf '%s' {1..49}, $'50\n')
-| 1,17,2,4,5,6,7,8,9,10,11,3,13,14,15,16,12,18,19,20,...,50

或者,如果您愿意,可以将每对变换写入一个变量:

awk -F, -v OFS=, -v xform='2,17 3,2 12,3 17,12' '
  BEGIN {n=split(xform,a,/[, ]/); for(i=1;i<=n;i+=2) c[a[i]]=a[i+1]}
  {for(i=1;i<=NF;i++) printf("%s%s", (i in c)?$(c[i]):$i, i<NF?OFS:ORS)}
' < <(printf '%s' {1..49}, $'50\n')
-| 1,17,2,4,5,6,7,8,9,10,11,3,13,14,15,16,12,18,19,20,...,50
csga3l58

csga3l582#

你可以让变量成为awk脚本的一部分,例如:

VAR_INP='TMP1=$1 ; TMP2=$2 ; TMP3=$3 ; TMP4=$4 ; $1=TMP1 ;$3=TMP2 ;$2=TMP3 ;$4=TMP4 ;'
awk -F, -v OFS=, '{'"$VAR_INP"'}1' input.csv

input.csv包含A,C,B,D时的输出:

A,B,C,D
puruo6ea

puruo6ea3#

跳过所有循环,只使用动态生成的硬编码字段:

__=' +. abc-d+ef1 3 2 4=:_'; # output field order, i.e. $1, $3, $2, $4 
                             # the extra junk is to showcase your
                             # choice of delimiter doesn't matter
echo 'A,C,B,D' | gawk -p- -f <( echo "$__" | 

mawk 'NF && sub("^" FS, "BEGIN { FS = OFS = \",\" } { print $",
                $!NF--)' FS='[^0-9]*' OFS=', $' ORS=' }'      )
A,B,C,D

# gawk profile, created Sat Aug 19 03:17:40 2023

# BEGIN rule(s)

BEGIN {
 1      FS = OFS = ","
}

# Rule(s)

 1  {
 1      print $1, $3, $2, $4
}

你可以用你喜欢的任何数量的字段来做,包括巨大的字段:

BEGIN { FS = OFS = "," } { print \
                                  \
$128188782,  $85722244,   $123534282,
$37670758,   $60028290,   $131921030,  $101600037,  $53589940,   $48298302,
$153042678,  $100120464,  $107851922,  $11180872,   $65049972,   $153695364,
$138511919,  $15813948,   $24186787,   $83253374,   $25331659,   $59136350,
$19155798,   $85377535,   $11588418,   $28771828,   $152162471,  $31367900,
$157916915,  $105161093,  $106673752,  $61974950,   $123484701,  $149790557,
$7895384,    $87583052,   $138512906,  $89536263,   $115174743,  $106171832,
$81369675,   $20925017,   $69480437,   $111922213,  $73729383,   $138292988,
$103837216,  $118998152,  $143126137,  $147159039,  $112103403,  $28084640,
 \
$140289494,  $81098056,   $94239552,   $48406403,   $95537055,   $151629955,
$79774382,   $96998304,   $37622857,   $6383655,    $75182254,   $65407607,
$126343621,  $133931881,  $44400227,   $115040821,  $133023592,  $7542040,
$109635804,  $33383263,   $152010293,  $105053789,  $152921533,  $62330336,
$81886602,   $43712923,   $35282544,   $124629910,  $118978754,  $134056479,
$76601479,   $149677984,  $134249451,  $35652544,   $85671151,   $7297972,
$65195787,   $136249090,  $160250689,  $99290903,   $93957377,   $89791229,
$59674074,   $98419844,   $22061410    }
single quotes are safely omitted since generated code fed via -f <( ) construct

相关问题