【问题标题】:How do I get AWK to reaarrange and manipulate text in a file to two output files depending on conditions?如何让 AWK 根据条件将文件中的文本重新排列和操作为两个输出文件?
【发布时间】:2022-12-10 02:16:14
【问题描述】:

我试图找到一种有效的方法来将一个文件中的文本拆分然后重新组合成两个单独的文件。它有很多事情要做,比如删除小数点,在金额字段和填充中反转符号(+ 变成 - 和 - 变成 +)。例如:

输入文件input.txt

(第一行只是为了更容易地给出字符位置而不是计数,它不存在于输入文件中,“|”只是为了说明位置而已)

1234567890123456789012345678901234567890123456789012345678901234567890123456789012345
           |         |             |     |               |                    |     |  ("|" shows position)
123456789XXPPPPPPPPPP              NNNNNN#1404.58        #0.00                0     1
987654321YYQQQQQQQQQQ              NNNNNN#-97.73         #-97.73              1     1
777777777XXGGGGGGGGGG              NNNNNN#115.92         #115.92              0     0
888888888YYHHHHHHHHHH              NNNNNN#3.24           #3.24                1     0

上面第 85 个字符包含“1”的任何行都会转到一个文件,例如 OutputA.txt 重新排列如下:

PPPPPPPPPP~~NNNNNN123456789XX~~~-0000140458-0000000000
QQQQQQQQQQ~~NNNNNN987654321YY~~~+0000009773+0000009773

以及任何包含“0”的行,因为上面的第 85 个字符会转到另一个文件 OutputB.txt,重新排列如下:

GGGGGGGGGG~~NNNNNN777777777XX~~~-0000011592-0000011592
HHHHHHHHHH~~NNNNNN888888888YY~~~-0000000324-0000000324

这看起来很复杂,但如果我可以将输入行的每一部分作为不同的变量,然后以不同的顺序将它们写出来,右对齐用 0 填充的数量,并根据最后一列将它们拆分成不同的文件。不确定如何将所有这些东西一次性放在一起。

我尝试根据第 85 个字符是 1 还是 0 将每一行打印到不同的文件中,然后尝试创建变量,比如从第一个字符到第 11 个字符是 varA,接下来的 10 个是 varB 等......但它变得复杂很快,因为我需要将 + 更改为 - 并将 - 更改为 +,然后用零填充并更改间距。它有点生气。这应该可以通过一个脚本实现,但我无法将所有部分放在一起。

我一直在寻找教程,但似乎没有任何内容涵盖基于条件的抓取,同时填充、重新排列、拆分等。

提前谢谢了

【问题讨论】:

  • 请更新问题以显示您的编码尝试以及您的代码生成的(错误)输出

标签: linux bash shell awk


【解决方案1】:

分裂

使用 GNU AWK ability to print to file,考虑以下简单示例

seq 20 | awk '$1%2==1{print $0 > "fileodd.txt"}$1%2==0{print $0 > "fileeven.txt"}'

它读取 seq 20 的输出(数字从 1 到 20,包括在内,每个数字在单独的行上)并将奇数放入 fileodd.txt 并将偶数放入 fileeven.txt

重组文本

使用 substr 和字符串连接来完成该任务,考虑下面的简单示例,假设您有 file.txt 和 DD-MM-YYYY 日期,就像这样

01-29-2022
01-30-2022
01-31-2022

但你想要 YYYY-MM-DD 那么你可以通过

awk '{print substr($0,7,4) "-" substr($0,1,2) "-" substr($0,4,2)}' file.txt

给出输出

2022-01-29
2022-01-30
2022-01-31

substr参数是:字符串($0是整行),起始位置和长度,空格是连接符。

去除小数点

使用 gsub 并将第二个参数设置为空字符串以删除不需要的字符,但请记住 . 在正则表达式中具有特殊含义,请考虑以下简单示例,让 file.txt 内容为

100.15
200.30
300.45

然后

awk '{gsub(/[.]/,"");print}' file.txt

给出输出

10015
20030
30045

观察使用的是 /[.]/ 而不是 /./ 并且 gsub 确实就地更改了。

反转符号(...)填充

乘以 -1,然后将 sprintfsuitable modifier 一起使用,考虑以下示例,让 file.txt 内容为

1
-10
100

然后

awk '{print "Reversed value is " sprintf("%+05d",-1*$1)}' file.txt

给出输出

Reversed value is -0001
Reversed value is +0010
Reversed value is -0100

解释:% - 这是将插入值的地方,+ - 使用-+作为前缀,05 - 用前导零填充 5 个字符的宽度,d 假设值为整数. sprintf 确实返回格式化的字符串,它可以与其他字符串连接,如上所示。

(在 GNU Awk 5.0.1 中测试)

【讨论】:

  • 感谢您的全面回答。我想我可以把它放在一起使它一切正常。
【解决方案2】:

您可以使用jq 来完成这项任务:

#!/bin/bash

INPUT='
123456789XXPPPPPPPPPP              NNNNNN#1404.58        #0.00                0     1
987654321YYQQQQQQQQQQ              NNNNNN#-97.73         #-97.73              1     1
777777777XXGGGGGGGGGG              NNNNNN#115.92         #115.92              0     0
888888888YYHHHHHHHHHH              NNNNNN#3.24           #3.24                1     0
'

convert() {
  jq -rR --arg lineSelector "$1" '
  def transformNumber($len):
    tonumber |                                    # convert string to number
    (if . < 0 then "+" else "-" end) as $sign |   # store inverted sign
    if . < 0 then 0 - . else . end |              # abs(number)
    . * 100 |                                     # number * 100
    tostring |                                    # convert number back to string
    $sign + "0" * ($len - length) + .;            # indent with leading zeros

  # Main program
    split(" ") |                                  # split each line by space
    map(select(length > 0)) |                     # remove empty entries
    select(.[4] == $lineSelector) |               # keep only lines with the selected value in last column

    # generate output                               # example for first line
    .[0][11:21] +                                   # PPPPPPPPPP
    "~~" +                                          # ~~
    (.[1] | split("#")[0]) +                        # NNNNNN
    .[0][0:11] +                                    # 123456789XX
    "~~~" +                                         # ~~~
    (.[1] | split("#")[1] | transformNumber(10)) +  # -0000140458
    (.[2] | split("#")[1] | transformNumber(10))    # -0000000000
  ' <<< "$2"
}

convert 0 "$INPUT"   # or convert 1 "$INPUT"

0 的输出

GGGGGGGGGG~~NNNNNN777777777XX~~~-0000011592-0000011592
HHHHHHHHHH~~NNNNNN888888888YY~~~-0000000324-0000000324

1 的输出

PPPPPPPPPP~~NNNNNN123456789XX~~~-0000140458-0000000000
QQQQQQQQQQ~~NNNNNN987654321YY~~~+0000009773+0000009773

【讨论】:

    猜你喜欢
    • 2015-05-06
    • 1970-01-01
    • 2023-03-11
    • 2018-01-02
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    • 2019-06-14
    • 1970-01-01
    相关资源
    最近更新 更多