【问题标题】:AWK: Reading all lines & manipulating one file ENTIRELY based each line of another fileAWK:读取所有行并完全基于另一个文件的每一行操作一个文件
【发布时间】:2020-04-19 04:55:46
【问题描述】:

我有两个输入文件:

文件1.txt:

Name    Latin-small    Roman        Latin-caps #header, not to be processed
F0,        a,              I,            A
F1,        b,              II,           B
F2,        c,              III,          C
F3,        d,              IV,           D

文件2.txt:

Lorem ipsum
Roman here.
LCaps here.
LSmall here.
Lorem ipsum
  1. 我从File1.txt 的每一行(script.sh 的第 6 行)中获得了 RLCLS 的赋值。
  2. 使用File1.txtscript.sh 的第 7 行)生成名为 Fx 的文件夹,其中 x=0, 1, 2, 3,...。
  3. 使用 File2.txt 生成的名为 Fx.txt 的单个文件必须放在这些文件夹中(script.sh 的第 7 行)。
  4. 现在,在读取File1.txt 的单行之后,它应该读取(script.sh 的第 7 行)并修改整个File2.txt 查看键。 这是我无法让它工作的地方,它为File1.txt 的每一行读取一行File2.txt
  5. 这些文件的内容基本上是File.txt的副本,除了here的值,使用键RomanFile1.txt的$3)、LCapsFile1.txt的$4)和@修改987654349@(File1.txt 中的 2 美元)用于每个目录中的每个 Fx.txt,使用在第一步中从 File1.txt 分配的值(script.sh 的第 9-17 行)。

如何使用在各个文件夹中获取以下输出(例如文件夹F2中的输出文件)

F0/F0.txt

 Lorem ipsum
 Roman               I.
 LCaps           A.
 LSmall         a.
 Lorem ipsum

或者,

F3/F3.txt

 Lorem ipsum
 Roman               IV.
 LCaps           D.
 LSmall         d.
 Lorem ipsum

或者,

F2/F2.txt

 Lorem ipsum
 Roman III.
 LCaps C.
 LSmall c.
 Lorem ipsum

更多信息File1 约为 300 行,对于每一行(标题除外),将在每个文件夹中创建一个文件。 File2 约为 200 行。每个短语RomanLSmallLC 随机出现在File2.txt 的某些行中,但不超过一行。这些是修改 `

中值的键

提前致谢!这个问题是更大工作流程的一部分。

EDIT2:试用码

脚本.sh

awk 'BEGIN {FS=","}
 {
  if ($1 !~ "F")
    {}
  else if ($1 ~ "F")
    {LS = $2; R = $3; LC = $4;
    system("mkdir "$1); filename=$1"/"$1".txt";
    {(getline < "File2.txt");
      {
        if ($0 ~ "Roman")
          {gsub("here",R); print >> filename;}
        else if ($0 ~ "LSmall")
          {gsub("here",LS); print >> filename;}
        else if ($0 ~ "LCaps")
          {gsub("here",LC); print >> filename;}
        else
          {print >> filename;}
      }
    }
    }
  }
' File1.txt

我正在获取所需的文件夹和文件结构(文件夹 Fx 中的文件 Fx.txt,其中 x = 0、1、2、...),但这些文件的内容是:

F0/F0.txt

Lorem ipsum

F1/F1.txt

Roman               II.

F2/F2.txt

LCaps           C.

F3/F3.txt

LSmall         d.

关键是awk读取整个file2.txt,同时读取file1的每一行并进行修改并将新文件放入相应的文件夹中。

【问题讨论】:

  • 目标有点类似于 [stackoverflow.com/questions/57234705/…(通过比较文件 2 的所有行与文件 1 的每一行来读取两个文件),但这里需要由 AWK 完成。
  • 我不明白输出是如何生成的,应该放在哪里。为什么file2?为什么文件夹F2 不是F0?为什么是Greek III,为什么是III 而不是I
  • @stackoverflow.com/users/1765658/f-hauri,添加了我的代码得到的输出。更正了文字中的错误。
  • @stackoverflow.com/users/9072753/kamilcuk,我添加了更多细节,希望它能澄清。这也有点复杂,从我这边正确传达。请随时询问更多信息。
  • 只需 @user ping 用户,无需复制配置文件 URL,事实上这可能会阻止 ping 工作。但无论如何,现在可能不需要 ping 这些用户。

标签: awk shell awk scripting


【解决方案1】:

正如您所发现的,Awk 一次只能处理一行。但我们可以反过来,将输入文件读入内存,然后在读取另一个文件时反复循环它的行。

您的示例在 file1.txt 中的项目之间有一个逗号和一个空格,但我认为这不是硬性要求,因此该脚本需要制表符分隔的输入。

awk -F "\t" 'BEGIN { split(":LSmall:Roman:LCaps", k, /:/) }
    NR==FNR { a[NR] = $0; n=NR; next }
    FNR==1 { next }  # skip header
    {
        system("mkdir "$1)
        filename=$1"/"$1".txt"        
        for(i=1; i<=n; i++) {
            line = a[i]
            for (j=2; j<=NF; ++j) {
                if (line ~ k[j]) {
                    gsub(/here/, $j, line)
                    break
                }
        }
        print line >>filename }
    }' file2.txt file1.txt

BEGIN 块使用替换键名称 k 初始化一个数组。为了使其与file1.txt 中的字段保持同步,第一项k[1] 为空(它没有指定替换键)。

NR==FNR 我们正在读取第一个输入文件时。我们只需将其行收集到数组a

当我们失败时,我们正在读取第二个文件,它是带有目录名称和替换的映射。对于每个输入行,我们遍历a 中的所有行并执行在当前行中的字段中指定的任何替换(一旦找到,我们就认为自己完成了。也许您想更改它以便多个键可以在同一行触发),最后将结果打印到指定的输出文件中。

您会注意到我们如何提取第一个字段并遍历后续字段,通过索引在 k 中查找它们对应的键。

演示:https://ideone.com/syTv99

如果您想对数百个文件执行此操作,可能会将部分或全部周围的循环重构为 shell 脚本,并专注于 Awk 脚本中的替换操作。 shell 也可以轻松地循环 file1.txt 中的数据,这将在一定程度上简化 Awk 脚本并使整个过程更容易理解。

# Trim the obnoxious header
tail -n +2 file1.txt |
while read -r directory LSmall Roman LCaps; do
    mkdir "$directory"
    awk -v LSmall="$LSmall" -v Roman="$Roman" -v LCaps="$LCaps" '
        BEGIN { split("LSmall:Roman:LCaps", k, /:/)
            split(LSmall ":" Roman ":" LCaps, r, /:/) }
        {
            for (j=1; j<=3; ++j)
                if ($0 ~ k[j]) {
                    gsub(/here/, r[j])
                    break
                }
        }1' file2.txt >"$directory"/"$directory".txt
done

演示:https://ideone.com/RUhsUS

【讨论】:

    猜你喜欢
    • 2013-04-07
    • 1970-01-01
    • 2018-07-22
    • 2018-06-01
    • 2017-03-05
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多