![我需要迭代两个文本文件和一个 shell 脚本](https://linux22.com/image/209702/%E6%88%91%E9%9C%80%E8%A6%81%E8%BF%AD%E4%BB%A3%E4%B8%A4%E4%B8%AA%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%E5%92%8C%E4%B8%80%E4%B8%AA%20shell%20%E8%84%9A%E6%9C%AC.png)
我的第一个文件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
在内存中,这对于大文件可能是一个问题。如果这是一个问题,那么您将需要一种不同的方法,但这超出了当前问题的范围。