【问题标题】:How do I add two lines from two files to a single command?如何将两个文件中的两行添加到单个命令中?
【发布时间】:2016-12-26 05:32:33
【问题描述】:

我仍然在空闲时间学习 bash,我想做的是格式化一个文件,该文件列出一次两行直接相关的数据,并将这些数据插入到单个命令中......对于示例:我的列表文件 -

line 1 data
line 2 data related to line 1
line 3 data
line 4 data related to line 3

现在我要做的是找到一种方法将两个相关行添加到单个命令中,并继续将接下来的两行添加到所述命令等中,直到列表完成。数据将作为选项插入到命令中...

COMMAND --OPTION1=line1data --OPTION2=line2data

列表不应重复,任何数据行均不应重复。到目前为止,我所做的是使用 grep 将文件格式化为两个单独的文件,第一个文件仅列出第一行数据(没有以下第二行相关数据),即 line1 line3 line5 等,第二个文件由第二行相关数据的列表组成,即 line2 line4 等......现在我可能会让这个 waaaay 对自己来说很难,但我试图使用类似 for 命令的东西将两个文件中的数据放入命令中循环该过程...但我不知道如何获取每个格式化文件的第一行(然后获取每个文件的下一行)并将其插入到一个命令中...

所以我来了。另外,有没有办法让这更容易,并且一次只从文件中获取两行数据并将其输入到命令中?提前致谢

【问题讨论】:

    标签: linux bash shell


    【解决方案1】:

    一种方法是这样的:

    while read opt1; do
      read opt2
      COMMAND --OPTION1="$opt1" --OPTION2="$opt2"
    done < input.txt
    

    你大概可以看到这里的逻辑——我们有一个循环,将一行读入变量opt1,其中循环中的第一个命令将下一行读入变量opt2,然后使用这两个变量来构建你的命令行。通过这种方式,它是 bash(或 POSIX shell 中的一个简单的单行代码——这里没有什么是 bash 独有的)。

    解决此问题的另一种方法是使用paste 命令,它严格来说不是 bash 的一部分,但随您的操作系统提供。请注意以下几点:

    $ printf '1\n2\n3\n4\n5\n6\n' | paste - -
    1   2
    3   4
    5   6
    

    这并没有按照您在问题中表达的方式分开使用的东西,因此需要一个更复杂的循环。 paste 默认使用 tab 作为分隔符。假设您的输入数据不包含制表符,您可以使用如下构造:

    while IFS=$'\t' read opt1 opt2; do
      COMMAND --OPTION1="$opt1" --OPTION2="$opt2"
    done < <(paste - - < input.txt)
    

    这里的逻辑是paste 命令将为我们的read 命令构造单行输入,这会将其IFS 设置为paste 使用的相同分隔符。 &lt;( ... ) 构造在 bash 中称为“Process Substitution”(您可以在手册页中找到它),如果您希望 while 循环填充稍后将在 shell 脚本中使用的变量,这将很有帮助。但是你可以通过使用管道来避免这里的 bashism:

    paste - - < input.txt | while IFS=$'\t' read opt1 opt2; do
      COMMAND --OPTION1="$opt1" --OPTION2="$opt2"
    done
    

    请注意,用于生成选项卡的构造 $'\t'(通常称为“格式替换”,但在 bash 手册页的“QUOTING”部分中进行了描述)也可能不是通用的,但在许多其他 shell 中确实存在除了 bash,它还是相当便携的。

    虽然它有点长并且涉及一个额外的命令,但我认为第二种方法是最清晰易读的。您应该使用对您最有意义的任何方法,以便您以后可以更轻松地维护它。

    考虑使用-r 选项进行读取、处理反斜杠和续行是有益还是有问题。我不知道您的用例,所以除了您知道之外,我无法对此提出建议。

    【讨论】:

      【解决方案2】:

      假设你的文件input.txt 有以下内容

      1
      2
      3
      4
      5
      6
      7
      8
      

      使用awk 命令访问各个行,如下所示:

      awk '{if(NR%2 == 0) {print "COMMAND --OPTION1="data1" --OPTION2="$0;}else{data1=$0;}}' input.txt

      在上面的awk 命令中,NR 是保存当前行号的变量。 $0 是完整的一行。

      NR%2 表示使用 mod % 运算符检查NR 给出的行号是否可以被2 整除。

      • 如果NR%2 equals 0NR 给出的行都是偶数,即2、4、6、8...

      • 如果NR%2 not equals 0NR 给出的行都是奇数,即1、3、5、7...

        Output:    
        COMMAND --OPTION1=1 --OPTION2=2
        COMMAND --OPTION1=3 --OPTION2=4
        COMMAND --OPTION1=5 --OPTION2=6
        COMMAND --OPTION1=7 --OPTION2=8
        

      【讨论】:

      • 是的,这就像一个魅力!现在...你能给我解释一下 % 符号吗?另外,我假设在 bash {} 中使用的括号只能包含数字字段,例如 {1..5} 等...感谢您的回答!
      • @NathanielDavidson,这个答案在awk 中为您提供了解决方案,而不是在bash 中。花括号在不同语言中的作用不同。您可能想man awk 了解一下这种语言的工作原理。
      • 如何处理选项中的空格或全局字符或引号? (答案:你不能不疯狂地增加脚本的复杂性)。底线:这不是一个好方法,它将数据序列化为代码,而不是将数据视为数据。
      • @gniourf_gniourf:“它将数据序列化为代码,而不是将数据视为数据”。需要注意的地方。谢谢 :-) 但同样,数据将被读取并需要格式化。所以当我们说“格式化”时,代码确实会参与到这个过程中。
      • @gniourf_gniourf:“最终”部分让事情变得清晰 :)
      猜你喜欢
      • 2016-02-04
      • 1970-01-01
      • 2017-12-16
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多