Bash 重新排列文本文件中的列;“定制订单”;使用Shell脚本
我有一个以制表符分隔的文本文件,名为“data.txt”,它看起来像 data.txtBash 重新排列文本文件中的列;“定制订单”;使用Shell脚本,bash,shell,awk,Bash,Shell,Awk,我有一个以制表符分隔的文本文件,名为“data.txt”,它看起来像 data.txt col2 col3 col4 col1 val1 val5 val9 val13 val2 val6 val10 val14 val3 val7 val11 val15 val4 val8 val12 val16 ... 我有一个数组col\u order=[col1,col2,col3,col4] 目标是使用shell脚本根据数组“col_order”
col2 col3 col4 col1
val1 val5 val9 val13
val2 val6 val10 val14
val3 val7 val11 val15
val4 val8 val12 val16
...
我有一个数组col\u order=[col1,col2,col3,col4]
目标是使用shell脚本根据数组“col_order”中的顺序重新排列“data.txt”中的列
最终产量
col1 col2 col3 col4
val13 val1 val5 val9
val14 val2 val6 val10
val15 val3 val7 val11
val16 val4 val8 val12
我目前的进展
awk 'BEGIN{ORS=RS="\n"; S=OFS="\t"}{for (i=1; i<=NF; i++) {f[$i] = i}{ print $(f["col1"]),$(f["col2"]),$(f["col3"]),$(f["col4"])}}' data.txt> data_corrected.txt
awk'BEGIN{ORS=RS=“\n;S=OFS=“\t”}{for(i=1;i请尝试以下内容
cat script.bash
List=( col1 col2 col3 col4 )
##echo ${List[*]}
awk -v bash_arr_val="${List[*]}" '
BEGIN{
num=split(bash_arr_val,array," ")
for(i=1;i<=num;i++){
array_with_bash_values_as_index[array[i]]=i
}
}
FNR==1{
for(i=1;i<=NF;i++){
if($i in array_with_bash_values_as_index){
actual_array[array_with_bash_values_as_index[$i]]=i
}
}
}
{
for(i=1;i<=num;i++){
printf("%s%s",$actual_array[i],i==NF?ORS:OFS)
}
}
' Input_file
Ed Morton编辑变量名称建议:
$ cat tst.awk
BEGIN{
numOutFlds = split(bash_arr_val,outNr2name)
for ( outNr=1; outNr<=numOutFlds; outNr++ ) {
fldName = outNr2name[outNr]
name2outNr[fldName] = outNr
}
}
FNR==1 {
for ( inNr=1; inNr<=NF; inNr++ ) {
fldName = $inNr
outNr = name2outNr[fldName]
outNr2inNr[outNr] = inNr
}
}
{
for ( outNr=1; outNr<=numOutFlds; outNr++ ) {
inNr = outNr2inNr[outNr]
fldValue = $inNr
printf "%s%s", fldValue, (outNr<numOutFlds ? OFS : ORS)
}
}
$ awk -v bash_arr_val='col1 col2 col3 col4' -f tst.awk file
col1 col2 col3 col4
val13 val1 val5 val9
val14 val2 val6 val10
val15 val3 val7 val11
val16 val4 val8 val12
$cat tst.awk
开始{
numOutFlds=拆分(bash_arr_val,outNr2name)
对于(outNr=1;outNr这不是最终解决方案,而是采购订单代码的改进,其中列顺序不是硬编码的:
#!/bin/bash
col_order=$1
awk -v col_order_string="$col_order" -v OFS='\t' '
BEGIN {
split(col_order_string, col_order, ",");
}
NR == 1 {
for (i=1; i<=NF; i++) {
f[$i] = i
}
}
{
s = ""
for (i=1; i <= NF; i++) {
printf "%s%s", s, $(f[col_order[i]]);
s = OFS
}
printf "\n"
}
' data.txt
欢迎来到SO,on SO,我们鼓励用户添加他们为解决自己的问题所付出的努力,所以请添加同样的努力,然后让我们知道。awk是您在这里的朋友。wrt我有一个数组
-一个shell数组还是一个awk数组?@EdMorton shell数组。尝试有意义的数组名称,比a更好
,b,
,等等!FWIW当我为刚从一个值映射到另一个值的数组命名时,我尝试根据映射的内容来命名它们。例如array[]
将输出字段号映射到字段名,所以我将其命名为outNr2name[]
,然后array_,并将_bash_值作为_索引[]
将字段名称映射到输出字段编号,因此我将其命名为name2outNr[]
和实际数组
将输出字段编号映射到输入字段编号,因此它将是outnr2inr[]
。然后当您编写类似outnr2inr[name2outNr[$I]的语句时=i
与实际数组[array\u with_bash\u values\u as_index[$i]]=i
相比,你所做的事情一眼就清楚多了。printf(“%s%s”,$(outNr2inNr[i]),i==NF ORS:OFS)
vsprintf(“%s%s”,$actual\u数组[i],i==NF ORS:OFS)
如果你为了锦上添花而使用变量名,比如outNr
和inNr
而不是i
,并在循环内部设置/使用一个临时变量fldName
而不是直接使用$i
,那么一切都会变得非常清晰。@EdMorton,是的,先生;我正在学习它,威尔尝试进一步改进,先生。您介意我编辑您的答案,以显示我将如何使用这些名称编写脚本吗?您可以再次删除它,或者以后对它执行任何您喜欢的操作。@EdMorton,当您编辑我的答案时,我会介意的?“这永远不会发生,先生”,请随时随意编辑,先生,请执行。
$ cat tst.awk
BEGIN{
numOutFlds = split(bash_arr_val,outNr2name)
for ( outNr=1; outNr<=numOutFlds; outNr++ ) {
name2outNr[outNr2name[outNr]] = outNr
}
}
FNR==1 {
for ( inNr=1; inNr<=NF; inNr++ ) {
f[name2outNr[$inNr]] = inNr
}
}
{
for ( outNr=1; outNr<=numOutFlds; outNr++ ) {
printf "%s%s", $(f[outNr]), (outNr<numOutFlds ? OFS : ORS)
}
}
$ awk -v bash_arr_val='col1 col2 col3 col4' -f tst.awk file
col1 col2 col3 col4
val13 val1 val5 val9
val14 val2 val6 val10
val15 val3 val7 val11
val16 val4 val8 val12
#!/bin/bash
col_order=$1
awk -v col_order_string="$col_order" -v OFS='\t' '
BEGIN {
split(col_order_string, col_order, ",");
}
NR == 1 {
for (i=1; i<=NF; i++) {
f[$i] = i
}
}
{
s = ""
for (i=1; i <= NF; i++) {
printf "%s%s", s, $(f[col_order[i]]);
s = OFS
}
printf "\n"
}
' data.txt
./script 'col1,col2,col3,col4'