【问题标题】:Copy each line of file1 into every other line of file2 (Python)将 file1 的每一行复制到 file2 的每一行(Python)
【发布时间】:2015-01-17 13:02:32
【问题描述】:

对不起这个荒谬的标题;这可能是我在 Google 上找不到答案的原因。

我有 5 个文本文件要合并为 1 个。我想要这样的格式:

line1 of file1
line1 of file2
line1 of file3
line1 of file4
line1 of file5
line2 of file1
line2 of file2
line2 of file3
line2 of file4
line2 of file5

等等。

我尝试使用下面的 bash 命令,但对于 sed 或其他东西来说似乎太多了:它只是将文本插入第一行,而不是我正在调用的变量的行。

for ((num=1; num<=66; num++)) ; do
    queryline=$(sed -n "${num}p" "file2.txt")
    sed -i "${num}i ${queryline}" "file1.txt"
done

(我也试过了)

for ((num=1; num<=66; num++)) ; do
    numa=$((num + 1))
    queryline=$(sed -n "${num}p" "file2.txt")
    sed -i "${numa}i ${queryline}" "file1.txt"
done

我认为使用 python (3.4) 可能会更容易,但我不知道该怎么做。请任何人提供提示?

【问题讨论】:

  • 每次都以追加模式打开合并文件。并复制第一个文件插入所有内容。要复制第二个文件,请转到每一行的末尾并从第二个文件追加一行。并且为了复制第三个文件,转到每第二行的末尾并从第三个文件中追加一行。同样,您可以分别在第三和第四的末尾复制第四和第五。
  • @gniourf_gniourf past 在这种情况下是最简单和最好的解决方案。如果 OP 喜欢对数据进行更多测试,这可能不是最好的。但无论如何,您应该将其作为解决方案发布,而不是作为评论。

标签: python bash file sed


【解决方案1】:

如果您确定您正好有 5 个文件,这将起作用。如果您需要对不同数量的文件进行这项工作,它会变得更加复杂。

with open("file1.txt") as f:
    file1 = f.readlines()
with open("file2.txt") as f:
    file2 = f.readlines()
with open("file3.txt") as f:
    file3 = f.readlines()
with open("file4.txt") as f:
    file4 = f.readlines()
with open("file5.txt") as f:
    file5 = f.readlines()
outfile = open("outfile.txt", "w")
for aline in [line for foo in zip(file1, file2, file3, file4, file5) for line in foo]:
    outfile.write(aline)
outfile.close()

【讨论】:

    【解决方案2】:

    使用 contextlib.ExitStack() 将输入文件作为一个组处理,并使用 zip 从所有文件中读取行:

    import contextlib
    import os
    
    filenames = ['a','b','c','d','e']
    output_file = 'fred'
    
    # setup files for test
    for filename in filenames:
        with open(filename, 'w') as fp:
            for i in range(10):
                fp.write('%s %d\n' % (filename, i))
    if os.path.exists('fred'):
        os.remove('fred')
    
    # open all the files and use zip to interleave the lines    
    with open(output_file, 'w') as out_file, contextlib.ExitStack() as in_files:
        files = [in_files.enter_context(open(fname)) for fname in filenames]
        for lines in zip(*files):
            # if you're not sure last line has a \n
            for line in lines:
                out_file.write(line)
                if not line.endswith('\n'):
                    out_file.write('\n')
            # if you are sure last line has a \n
            # out_file.write(''.join(lines))
    
    print(open('fred').read())
    

    【讨论】:

      【解决方案3】:

      您的 bash 不起作用,因为您试图插入在插入之前不存在的行中。

      echo "\n" > file_to_insert.txt
      for i in {1..5};do
        for((num=1;num<66;num++);do
          line_num=$((num*i)
          queryline=$(sed -n '${num}p' 'file${i}.txt'
          sed -i "${num}i '$queryline'" 'file_to_insert.txt'
      done
      

      【讨论】:

        【解决方案4】:

        这是一个gnu awk(gnu 对ARGIND(文件选择器)进行操作)

        awk -v t=5 '{c=c<FNR?FNR:c; for (i=1;i<=t;i++) if (ARGIND==i) a[i FS FNR]=$0} END {for (i=1;i<=c;i++) for (j=1;j<=t;j++) print a[j FS i]}' file1 file2 file3 file4 file5
        

        您将t 设置为文件数。

        例子:

        cat f1
        file1 one
        file1 two
        file1 three
        file1 four
        

        cat f2
        file2 one
        file2 two
        file2 three
        file2 four
        

        cat f3
        file3 one
        file3 two
        file3 three
        file3 four
        

        awk -v t=3 '{c=c<FNR?FNR:c; for (i=1;i<=t;i++) if (ARGIND==i) a[i FS FNR]=$0} END {for (i=1;i<=c;i++) for (j=1;j<=t;j++) print a[j FS i]}' f1 f2 f3
        file1 one
        file2 one
        file3 one
        file1 two
        file2 two
        file3 two
        file1 three
        file2 three
        file3 three
        file1 four
        file2 four
        file3 four
        

        它是如何工作的?

        awk -v t=3 '                    # Set t to number of files
            {c=c<FNR?FNR:c              # Find the file with most records and store number in c
            for (i=1;i<=t;i++)      # Loop trough one and one file
                if (ARGIND==i)          # Test what file we are on
                    a[i FS FNR]=$0}     # Stor data in array a
        END {
            for (i=1;i<=c;i++)          # Loop trough line number
                for (j=1;j<=t;j++)      # Loop trough file number
                    print a[j FS i]}    # Print data from array
        ' f1 f2 f3                      # Read the files
        

        【讨论】:

          【解决方案5】:

          实现您想要的一个很好的可能性是坚持使用标准实用程序:这里推荐paste(由 POSIX 指定):

          paste -d '\n' file1 file2 file3 file4 file5
          

          或者,如果你喜欢 Bashisms:

          paste -d '\n' file{1..5}
          

          这可以简单地推广到任意数量的文件。

          【讨论】:

            猜你喜欢
            • 2012-12-08
            • 2019-04-13
            • 2020-03-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-03
            • 2014-01-02
            • 1970-01-01
            相关资源
            最近更新 更多