AWK语句在代码中做循环for将某些字段大写

AWK Sentence doing looping for in the code to capitalize some fields

代码

awk '{for(i=1;i<=NF;++i){$i=toupper(substr($i,1,1))tolower(substr($i,2));}print}'

我需要在某些字段中将每个单词的第一个字符大写。 这个循环查找行中的所有字符并替换行中的第一个字符,如果它不在字段的第一位,则对行的其余部分执行 tolower 句子。 我需要这个循环的一些例子,但是只为某些字段(一个或多个)分配句子请解释答案以及它如何在所有行和字段上工作。

我已经看到没有循环执行此操作。

awk '{print toupper(substr([=11=],1,1))tolower(substr([=11=],2))}'

下面的部分占所有行,如果我更改某些字段,例如数字 2:

$>  echo 'Aaaa Bbbb Cccc DDDD Eeee Ffff Gggg HHHH'  | awk '{print toupper(substr([=12=],1,1)) tolower(substr(,2)) }'

$>  Abbb

$0 告诉对第一个字符的所有行做 toupper,下面的部分 ($0)(,1,1) 告诉它只为一个字符,最后指定这个做的长度 (1)但是下面的部分说它取自字段 2 的第二个字符并一起打印(因为语句被粘贴) 请告诉我,如果我在其中的某些地方有误,以及希望理解的解释。

我希望做 Toupper of Tolower 指定字段的句子。

预期示例:

只对这个 space 中的字段 4 和 8 进行大写,如前所示,或者在其他示例中,如果我有分号分隔字段,如何做到这一点,示例:

>$ echo 'Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH'

在第1场的第4个字和第3场的第2个字做同样的事情。 (现在字段以分号分隔)

结果:

Aaaa Bbbb Cccc Dddd;Eeee Ffff;Gggg Hhhh

或者您可以反过来将整行转换为小写,然后遍历将第一个字符转换为大写的字段,例如

awk '{
    sub([=10=],tolower([=10=]))
    for (i = 1; i <= NF; i++)
        sub(substr($i,1,1),toupper(substr($i,1,1)))
}1'

最后 '1' 仅提供整行的默认打印。

例子Use/Output

只需将其粘贴到您的终端,例如

$ echo 'Aaaa Bbbb Cccc DDDD Eeee Ffff Gggg HHHH' |
> awk '{
>     sub([=11=],tolower([=11=]))
>     for (i = 1; i <= NF; i++)
>         sub(substr($i,1,1),toupper(substr($i,1,1)))
> }1'
Aaaa Bbbb Cccc Dddd Eeee Ffff Gggg Hhhh

使用替代字段分隔符

根据您对问题的编辑,如果您有 "[ ;]" 的替代字段分隔符,您可以在 gawk 中使用字符列表指定替代分隔符,或者通过对分隔符进行“或”运算,例如

awk -F'[ ;]' '{
    sub([=12=],tolower([=12=]))
    for (i = 1; i <= NF; i++)
        sub(substr($i,1,1),toupper(substr($i,1,1)))
}1'

使用修改后的输入结果进行测试,例如

$ echo 'Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH' |
> awk -F'[ ;]' '{
>     sub([=13=],tolower([=13=]))
>     for (i = 1; i <= NF; i++)
>         sub(substr($i,1,1),toupper(substr($i,1,1)))
> }1'
Aaaa Bbbb Cccc Dddd;Eeee Ffff;Gggg Hhhh

仅影响第 4 和第 8 个字段

虽然没有直接询问,但不清楚您是要修改所有字段,还是在某些情况下只修改第 4 和第 8 个字段。如果您只想更改第 4 和第 8 个字段,而不管其他字段,您可以添加我在之前的编辑中提到的 modulo 检查以仅隔离这些字段。例如:

awk -F'[ ;]' '{
    for (i = 1; i <= NF; i++) {
        if (i % 4 == 0) {
            sub($i,tolower($i))
            sub(substr($i,1,1),toupper(substr($i,1,1)))
        }
    }
}1'

在这种情况下,所有其他字段将保持不变,并将第 4 和第 8 转换为 Titlecase,例如

$ echo 'aaaa bbbb cccc DDDD;eeee ffff;gggg HHHH' |
> awk -F'[ ;]' '{
>     for (i = 1; i <= NF; i++) {
>         if (i % 4 == 0) {
>             sub($i,tolower($i))
>             sub(substr($i,1,1),toupper(substr($i,1,1)))
>         }
>     }
> }1'
aaaa bbbb cccc Dddd;eeee ffff;gggg Hhhh

如果这还不能解决所有问题,请告诉我。

能否请您尝试以下。我试图制定非常通用的解决方案,我们可以在其中提及我们需要将第一个字符设为大写并将其余字符设为小写的字段值。

echo 'Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH WEEEEEwrwr' | 
awk -v convert="4,8,9" '
BEGIN{
  FS="[; ]"
  num=split(convert,array,",")
  for(i=1;i<=num;i++){
    found[array[i]]
  }
}
{
  for(i=1;i<=NF;i++){
    if(i in found){
      first=substr($i,1,1)
      second=substr($i,2)
      sub(first,toupper(first))
      sub(second,tolower(second))
    }
  }
}
1'

输出结果如下。

Aaaa Bbbb Cccc Dddd Eeee Ffff Gggg Hhhh Weeeeewrwr

我在这里扩展了你的例子(通过增加 1 个测试值),你也可以在 -v convert=":4,8,9...." 中以逗号分隔的形式提及所有字段编号以更改它们。



说明: 上面代码加说明,仅供说明,我没有运行检查 运行 是否也带有评论。

echo 'Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH WEEEEEwrwr' |      ##Printing strings with echo and sending its output to awk command.
awk -v convert="4,8,9" '                                         ##Starting awk program here and creating variable named convert whose value will be all fields where we need to make the changes with comma separated.
BEGIN{                                                           ##Starting BEGIN section here.
  FS="[; ]"                                                      ##Setting FS field separator as semi colon OR space here for all lines.
  num=split(convert,array,",")                                   ##splitting convert variable to array whose delimiter is comma.
  for(i=1;i<=num;i++){                                           ##Starting a for loop from i=1 to till value of num(which is total number of elements in array, above created)
    found[array[i]]                                              ##Creating array named found whose index is value of array[i].
  }
}
{
  for(i=1;i<=NF;i++){                                            ##Starting a for loop from value of 1 to till NF.
    if(i in found){                                              ##Checking if current field is same field which user wants to change, if yes then go ahead with further statements.
      first=substr($i,1,1)                                       ##Creating variable first whose value is 1st character of current field.
      second=substr($i,2)                                        ##Creating variable first whose value is from 2nd field to till complete value of current field.
      sub(first,toupper(first))                                  ##using sub for changing first to UPPER case.
      sub(second,tolower(second))                                ##using sub for changing second to LOWER case.
    }
  }
}
1'                                                               ##Mentioning 1 will print edited/non-edited lines here.

因为 Do the same in the 4th word of the field 1 and the 2nd in the 3rd field. 和其他答案以及您问题中的其他一些文本和示例建议您更改选定的 space-选定的分号分隔字段的分隔子字段以开始大写然后全部小写,这是一种方法:

$ cat tst.awk
BEGIN {
    split(nrs,tmp,/[ .]+/)
    for (i=1; i in tmp; i+=2) {
        tgtFldNrs[++numTgts]  = tmp[i]
        tgtSubFldNrs[numTgts] = tmp[i+1]
    }
    FS = OFS = ";"
    subFs = subOfs = " "
}
{
    for (tgtNr=1; tgtNr<=numTgts; tgtNr++) {
        fldNr    = tgtFldNrs[tgtNr]
        subFldNr = tgtSubFldNrs[tgtNr]

        numSubFlds = split($fldNr,subFlds,subFs)
        subFld = subFlds[subFldNr]
        subFlds[subFldNr] = toupper(substr(subFld,1,1)) tolower(substr(subFld,2))

        fld = subFlds[1]
        for (subFldNr=2; subFldNr<=numSubFlds; subFldNr++) {
            fld = fld subOfs subFlds[subFldNr]
        }
        $fldNr = fld
    }

    print
}

鉴于此示例输入:

$ cat file
Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH

告诉awk更新字段1的子字段4(1.4)和字段3的子字段2(3.2)(来自问题中的Do the same in the 4th word of the field 1 and the 2nd in the 3rd field)将输出:

$ awk -v nrs='1.4 3.2' -f tst.awk file
Aaaa Bbbb Cccc Dddd;Eeee Ffff;Gggg Hhhh

希望这就是您想要做的,如果不是,请更新您的问题以阐明您的要求并提供更全面的示例 input/output。

您可以像下面这样尝试 Perl

$ echo 'Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH WEEEEEwrwr' | 
perl -0777 -nE ' @a=qw(4 8 9);%k = map {$_,1} @a; s/(\w+)/$i++; $k{$i}==1 ? "\u\L":/ge; print'
Aaaa Bbbb Cccc Dddd;Eeee Ffff;Gggg Hhhh Weeeeewrwr

或另一种方式

$ echo 'Aaaa Bbbb Cccc DDDD;Eeee Ffff;Gggg HHHH WEEEEEwrwr' | 
perl -0777 -nE ' @a=qw(4 8 9);@k{@a}=undef; s/(\w+)/$i++; exists $k{$i} ? "\u\L":/ge ; print '
Aaaa Bbbb Cccc Dddd;Eeee Ffff;Gggg Hhhh Weeeeewrwr

可以用 sed 完成:

  echo 'Aaaa Bbbb Cccc dDDD;Eeee Ffff;Gggg HHHH' | sed -r 's/([a-zA-Z]{1})([a-zA-Z]+)/\U\L/g'

解释:

  1. -r:用于扩展正则表达式

  2. 's/.../.../':代表替换

  3. ([a-zA-Z]{1}): 找到单词

  4. 第一个字符
  5. ([a-zA-Z]+): 单词的其余部分

  6. \U,\L: 改变字符大小写的运算符

  7. ...:表示在搜索部分找到的模式。

希望有用。