【问题标题】:multiple positional parameter assignment for "cut" command“cut”命令的多个位置参数分配
【发布时间】:2017-04-05 20:40:29
【问题描述】:

首先我想提前向你们所有人说声谢谢,我希望有一天能成为其中的一员。所以我有一个文件,它是 5 个参数长的行列表。比如

Bob:Wilson:Nebraska:34:yes

我需要在 BASH 中编写一个程序,让我可以水平查看标准输出,并允许我调用文件中的文本行,例如

$sh filename.sh 1
Bob
Tom
Dave
etc..

$sh filename.sh 1 3 4 2
Bob:Nebraska:34:Wilson
Tom:Iowa:27:Anderson
etc..

到目前为止我写的是

cut -d : -f$1,$2,$3,$4,$5 somefile.txt | paste -s

问题是如果用户在 sh filename.sh 之后输入少于 5 个参数,我会收到错误代码。用户不需要输入 5,但最多可以调用 5。

【问题讨论】:

    标签: bash


    【解决方案1】:

    awk 来救援!

    awk -F: -v c="$1 $2 $3 $4 $5" 'BEGIN {n=split(c,a," ")} 
                                         {for(i=1;i<n;i++) printf "%s", $a[i] FS; 
                                          printf "%s\n", $a[n]}' file
    

    如果您需要澄清,请尝试告诉我。

    【讨论】:

    • 我看到很多使用“awk”来回答这个板上的这些问题(我已经爬行了一段时间)但我们还没有在课堂上介绍它,所以我对它不够熟悉使用它,但非常感谢您的意见!我正在网上学习这个,它还有很多不足之处。
    【解决方案2】:

    就我个人而言,我总是避免使用 shell 脚本进行文本处理。有更好的工具,例如 sedawkperl 等等。这就是我在纯 bash 中的做法,因为这似乎是您正在寻找的 (*):

    #!/bin/bash
    #file: script.sh
    
    for line in $(<somefile.txt); do
       array=( ${line//:/ } )
       counter=1
       for elem in $@; do
          echo -n "${array[$elem-1]}"
          [ $counter -ne $# ] && echo -n ":"
          ((counter++))
       done
       echo
    done
    

    (*):不要被语法高亮所迷惑,它会将$# 之后的所有内容识别为注释(灰色文本)。示例脚本中的所有语法都是正确的。

    说明:

    脚本读取 somefile.txt,在 : 字符处分割每一行,并将生成的字段/元素存储在数组 array 中。然后它按照脚本参数 ($@) 指定的顺序输出字段。

    这是你想要的输出:

    $ ./script.sh 1
    Bob
    Tom
    
    $ ./script.sh 1 3 4 2
    Bob:Nebraska:34:Wilson
    Tom:Iowa:27:Anderson
    

    还要注意以下几点:

    在您的示例中,您可能使用 Bourne Shell (sh) 而不是 bash 执行脚本。然而,上面的脚本需要bash,因为它使用了substring replacement 功能。

    【讨论】:

      【解决方案3】:

      仅扩展现有参数

      IFS=,
      cut -d : -f"$*" somefile.txt
      

      $* 扩展为 1st parameter $IFS 2nd parameter $IFS ... $IFS last parameter,即 $1,$2 如果给定两个参数,$1,$2,$3 如果给定三个参数,以及以此类推。

      允许重新排列

      上面的命令有问题:cut 不能重新排列列。 cut -f1,2 等价于 cut -f2,1。见rearrange columns using cut。因此我们改用awk

      如果参数是filename.sh 1 3 4 2,那么我们需要下面的awk 命令:

      awk -F: -v OFS=: '{ print $1, $3, $4, $2 }' somefile.txt
      

      -F 设置读取文件的字段分隔符。 -v OFS=: 设置输出的字段分隔符。 print $1, $3, ... 表示 »打印第一个字段,然后是第三个,...«。请注意,'$1' 不是脚本的第一个参数,而是由 awk 解释的文字字符串。

      我们使用与以前相同的技巧从给定参数构建awk-command。

      IFS=,
      awk -F: -v OFS=: "{ print ${*/#/$} }" somefile.txt
      

      ${*/#/$}$ 添加到每个参数。扩展将是$1st parameter,$2nd parameter,...,$last parameter

      【讨论】:

      • 我忘了添加“。谢谢
      • 您的脚本没有给出请求的输出。当调用./script 1 3 4 2 时,它将输出Bob:Wilson:Nebraska:34 而不是Bob:Nebraska:34:Wilson
      • cut 无法更改字段的顺序。见this question。由于 Grunt 主要询问的是参数而不是实际切割,我认为这对他/她来说不是问题。但你是对的,我应该解决这个问题。
      • 感谢 inferno 让我知道 cut 不会重新排列顺序。
      猜你喜欢
      • 2013-11-06
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 2014-07-02
      • 2012-11-25
      • 1970-01-01
      相关资源
      最近更新 更多