Shell 如何用最后一个值替换整列?

Shell 如何用最后一个值替换整列?,shell,csv,awk,Shell,Csv,Awk,我试图获取CSV文件第三列中的最后一个值,然后用这个值替换整个第三列 我一直在尝试: var=$(tail -n 1 math_ready.csv | awk -F"," '{print $3}'); awk -F, '{$3="$var";}1' OFS=, math_ready.csv > math1.csv 但它不起作用,我不明白为什么 请帮忙 外壳变量在awk中不能在内部展开。您可以这样做: awk -F, -v var="$var" '{ $3 = var } 1' OFS=,

我试图获取CSV文件第三列中的最后一个值,然后用这个值替换整个第三列

我一直在尝试:

var=$(tail -n 1 math_ready.csv | awk -F"," '{print $3}'); awk -F, '{$3="$var";}1' OFS=, math_ready.csv > math1.csv
但它不起作用,我不明白为什么


请帮忙

外壳变量在awk中不能在内部展开。您可以这样做:

awk -F, -v var="$var" '{ $3 = var } 1' OFS=, math_ready.csv > math1.cs
您可能可以通过以下方式简化代码:

awk -F, 'NR == FNR { r = $3; next } { $3 = r } 1' OFS=, math_ready.csv math_ready.csv > math1.csv
输入示例:

1,2,1
1,2,2
1,2,3
1,2,4
1,2,5
输出:

1,2,5
1,2,5
1,2,5
1,2,5
1,2,5

试试这一行。它不依赖于列计数

var=`tail -1 sample.csv | perl -ne 'm/([^,]+)$/; print "$1";'`; cat sample.csv | while read line; do echo $line | perl -ne "s/[^,]*$/$var\n/; print $_;"; done


cat sample.csv
24,1,2,30,12
33,4,5,61,3333
66,7,8,91111,1
76,10,11,32,678
输出:

脚本的主要问题是试图访问awk脚本中的shell变量(
$var
)。Awk不是shell,它是一种完全独立的语言/工具,有自己的名称空间和变量。您无法在awk中直接访问shell变量,就像在C中无法访问它一样。要访问shell变量的值,您需要执行以下操作:

shellvar=27
awk -v awkvar="$shellvar" 'BEGIN{ print awkvar }'`
一些额外的清理:

  • 当FS和OFS具有相同的值时,不要将它们分别指定给该值,而是使用
    BEGIN{FS=OFS=“,”}
    ,以提高清晰度和可维护性
  • 不要在使用这些变量的脚本之后初始化变量,除非您有非常明确的理由这样做。使用awk-F-v OFS=…'脚本“将这些变量初始化为单独的值,而不是
    awk-F…”脚本'OFS=…
    ,因为在使用完代码段中的变量后,在代码段中初始化变量是非常不自然的,并且在执行BEGIN部分时,在末尾的args列表中初始化的变量没有初始化,这可能会导致错误

  • +1用于将仅适用于awk的解决方案与许多鲜为人知的功能结合使用谢谢!我更喜欢awk唯一的解决方案。但是你能详细解释一下它的逻辑吗?对不起,我是新来的shell编程人员;-)@Boriskryshev通过两次传递
    math_ready.csv
    我们让awk读两遍。节
    NR==FNR{r=$3;next}
    以第一个循环为目标。它将每行的第三列读取为
    r
    。最后一行将给出
    r
    的最后一个值
    {$3=r}1
    处理第二个循环。它用每行的
    r
    值替换第三列
    1
    1{print}
    同义,它总是为处理
    {print}
    提供一个真实的条件
    print
    打印当前记录。若要添加有关这两个部分如何分别处理两个会话的更多提示:
    NR==FNR{r=$3;next}
    NR==FNR
    仅在第一个会话内有效,因为NR即使在第二个会话上也会不断增加,但FNR会重置回0。这就是该条件在下一个会话中不再有效的原因
    next
    使
    awk
    跳转到下一条记录,而不处理其后的任何语句。实际上,这使得
    {r=$3}
    只为第一个循环运行,{
    {$3=r}1
    只为第二个循环运行…。我只是发现这使我的答案复杂化。在有人向我证明这是未定义的行为之前,我也是这样做的,因此在某些AWK中,
    ARGC++
    可以在赋值之前执行。从那时起,我通常使用
    ARGV[ARGC]=ARGV[ARGC-1];ARGC++
    。考虑到这一点,但我也认为我的脚本只针对gawk运行。诚然,这是一个非常简单的解决方案,尽管将其特定于gawk似乎不值得,因为没有任何只针对gawk的功能使脚本变得更简单。我想,这是一个非常简单的解决方案。
    awk '
        BEGIN { ARGV[2]=ARGV[1]; ARGC++; FS=OFS="," }
        NR==FNR { last = $3; next }
        { $3 = last; print }
    ' math_ready.csv > math1.csv
    
    shellvar=27
    awk -v awkvar="$shellvar" 'BEGIN{ print awkvar }'`