我需要迭代两个文本文件和一个 shell 脚本

我需要迭代两个文本文件和一个 shell 脚本

我的第一个文件screen.txt包含单个字母,例如:

d
m
a
o

第二个文件beta.txt包含很多行:

cvvbbe
etgjiua
qwrfggo

第三个文件gama.sh是一个shell脚本

beta.txt我需要按以下方式循环文件:

  • 将每行的最后一个字母替换beta.txt为第一个字母screen.txt
  • 节省beta.txt
  • 跑步gama.sh
  • 将每一行的最后一个字母替换beta.txt为第二个字母screen.txt
  • 节省beta.txt
  • 跑步gama.sh
  • 等等

答案1

使用任何 awk:

$ cat gama.sh
#!/usr/bin/env sh

awk '
    NR==FNR {
        beta[++nr] = substr($0,1,length($0)-1)
        next
    }
    {
        for ( i=1; i<=nr; i++ ) {
            print beta[i] $0 > ARGV[1]
        }
        print "" > ARGV[1]
    }
' "$@"

$ ./gama.sh beta.txt screen.txt

$ cat beta.txt
cvvbbd
etgjiud
qwrfggd

cvvbbm
etgjium
qwrfggm

cvvbba
etgjiua
qwrfgga

cvvbbo
etgjiuo
qwrfggo

上面假设 的内容beta.txt不是太大而无法放入内存,否则如果 的内容screen.txt适合内存则:

$ cat gama.sh
#!/usr/bin/env sh

tmp=$(mktemp) &&
awk '
    BEGIN { OFS="\t" }
    NR==FNR {
        screen[++nr] = $0
        next
    }
    {
        $0 = substr($0,1,length($0)-1)
        for ( i=1; i<=nr; i++ ) {
            print i, FNR, $0 screen[i]
        }
    }
    END {
        for ( i=1; i<=nr; i++ ) {
            print i, FNR+1
        }
    }
' "$@" |
sort -k1,2n |
cut -f3- > "$tmp" &&
mv -- "$tmp" "$2"

$ ./gama.sh screen.txt  beta.txt

$ cat beta.txt
cvvbbd
etgjiud
qwrfggd

cvvbbm
etgjium
qwrfggm

cvvbba
etgjiua
qwrfgga

cvvbbo
etgjiuo
qwrfggo

第二个脚本应用 DSU(装饰/排序/取消装饰)惯用法以所需的顺序生成输出行,请参阅https://stackoverflow.com/questions/71691113/how-to-sort-data-based-on-the-value-of-a-column-for-part-multiple-lines-of-af/71694367#71694367了解更多详情。

答案2

您可以sed循环运行,如下所示:

 $ while read letter; do 
    printf '%s\n\n' "$(sed "s/.$/$letter/" beta.txt)";
   done < screen.txt > tmpFile && mv tmpFile beta.txt

$ cat beta.txt
cvvbbd
etgjiud
qwrfggd

cvvbbm
etgjium
qwrfggm

cvvbba
etgjiua
qwrfgga

cvvbbo
etgjiuo
qwrfggo

如果您希望将其作为脚本,则可以将其另存为gamma.sh

#!/bin/sh

tmpFile=$(mktemp)
while read letter; do 
    printf '%s\n\n' "$(sed "s/.$/$letter/" beta.txt)";
done < screen.txt > "$tmpFile" && mv tmpFile 

请注意,对于大文件来说,这将非常慢且不切实际。对于您给出的虚拟示例来说这很好,但是如果您需要处理几千甚至数百行,则应该使用另一种语言。例如,在 Perl 中:

#!/usr/bin/perl
use strict;
use warnings;

my @letters;
open(my $letterFile, '<', "$ARGV[0]") or
    die("Failed to open letter file '$ARGV[0]':$!\n");
while (my $line = <$letterFile>) {
  chomp($line);
  $line =~ /(.)\s*$/;
  push @letters, $1;
}
close($letterFile);

open(my $dataFile, '<', "$ARGV[1]") or
    die("Failed to open data file '$ARGV[1]':$!\n");

my @data = <$dataFile>;
my $c = 0;
foreach my $letter (@letters) {
  print "\n" if $c;
  foreach my $line (@data) {
    $line =~ s/.$/$letter/;
    print "$line";
  }
  $c++;
}
close($dataFile);

如果将上面的脚本保存为foo.pl,您可以执行以下操作:

$ perl foo.pl screen.txt beta.txt
cvvbbd
etgjiud
qwrfggd

cvvbbm
etgjium
qwrfggm

cvvbba
etgjiua
qwrfgga

cvvbbo
etgjiuo
qwrfggo

请注意,这会将所有内容存储beta.txt在内存中,这对于大文件可能是一个问题。如果这是一个问题,那么您将需要一种不同的方法,但这超出了当前问题的范围。

相关内容