gpt4 book ai didi

linux - 使用 bash 脚本根据给定条件使用 sed 提取位置特定记录

转载 作者:太空宇宙 更新时间:2023-11-04 12:11:22 25 4
gpt4 key购买 nike

我想从一个 ASCII 文件中提取数据,该文件看起来像此处提供的以 1NAME 开头的 block 。以 1NAME 开头的 block 可以重复任意次数 - 我有一些文件只有一个 block ,而在某些文件中有多达 744 个 block :

AVERAGE   MODELNAME -- RUNNAME
0 1 11121 0. 11122 24.
-9700000 4000000 0 -241200000000 -1620000
1.00000 1000.00000 10 10 1 2 0 15. 11. 0.
1 1 500 400
NAME
11121 0.00 11121 1.00
1NAME
0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
NAME
11121 1.00 11121 2.00
1NAME
1.0000000E+00 45.0000000E+00 01.0000000E+00 115.0000000E+00 5.0000000E+00
2.0000000E+00 66.0000000E+00 09.0000000E+00 180.0000000E+00 4.0000000E+00
3.0000000E+00 80.0000000E+00 70.0000000E+00 130.0000000E+00 5.0000000E+00

我想从 (1) 文件中给定的重复位置中提取值,从“1NAME”之后开始,(2) 将输出通过管道传输到文本文件并创建 header 以标识从中提取的位置,以及 (3)创建一个自定义代码,可以在 1NAME 之后接收多个位置的输入(比如记录 1、5、8),并将它们输出到单独的输出(例如:位置 1 的所有记录的一个输出,位置 5 的一个输出文件,.. .).

举个例子,我想在给定的输入文件中的 1NAME 之后抓取记录 1、5 和 8。每条记录的输出应在标记为 GRID#.txt 的单独记录特定文本文件中输出如下:

GRID 1    
0.0000000E+00
00.0000000E+00
GRID 5
0.0000000E+00
5.0000000E+00
GRID 8
0.0000000E+00
09.0000000E+00

我能够使用 sed 一次提取数据。但是我需要从输入文件的多个位置提取数据。所以我试图将所有信息放在一个脚本中。以下是我采取的步骤。

  1. 输入文件有多个空格和不一致的空行。所以我用sed去掉多个空格换成一个空格。然后使用此步骤的管道输出,删除所有空行。这导致文件中的所有数据排列为每行一个值。

    sed 's/\s\+/\n/g' <input.txt>| sed '/^$/d
  2. 为了提取数据,我随后从步骤 1 的管道输出中使用了 sed 命令(格式如下)。

    sed -n -e 11p -e 50p
  3. 我尝试将所有这些命令作为具有自定义行号的 bash(或 csh,任一选项)脚本。我尝试(天真地)使用 foreach,然后了解到它不能在 bash 中使用。我将改用其他用户推荐的脚本。

    #!/bin/bash 
    set FILE=$cwd/sample_or_2day
    foreach GRID (23729)
    foreach GRIDTIME(28 41)
    sed 's/\s\+/\n/g' $FILE | sed '/^$/d' | sed '1,36d' > temp_out
    sed -n -e "$GRIDTIME" temp_out | tee $cwd/out_$GRID

感谢您的耐心等待。我是一个紧张的程序员,正在努力掌握基础知识。我花时间查看 sed 说明页面和用户支持论坛。欢迎任何建议——尤其是有明确说明的。谢谢!

最佳答案

您尝试使用 csh 脚本,但将您的问题标记为 bash。我用 bash 脚本回答。

您问题的核心是如何从格式化的打印输出中提取信息。通常,应该避免这种情况:应该使用了解正在操作的数据结构的编程环境,以避免在每一步都重新解析。然而,在现实世界中,这种情况经常出现,人们不得不应对它们。

您将所有空格转换为换行符的方法适用于您的情况。而不是多个 sed 命令,实现它的最快方法是通过

tr -s ' ' '\n'

(-s 选项将多次出现的目标字符压缩为一个,消除空行)

然后,您对第 7 行和第 14 行感兴趣,每次出现包含 1NAME 的行之后。这是在 sed 中完成的

sed -n -e '/^1NAME$/{n;n;n;n;n;n;n;p;n;n;n;n;n;n;n;p}'

这意味着:当您看到 1NAME 时,执行 nextline 命令七次,然后执行 print 命令。这样做两次。

您可以使用 shell 变量:

next7='n;n;n;n;n;n;n;p'

cat ./sample_or_2day | tr -s ' ' '\n' | sed -n -e '/^1NAME$/'"{$next7;$next7}"

会产生

0.0000000E+00
0.0000000E+00
66.0000000E+00
130.0000000E+00

正确,第一个 block 也被带入。要跳过它,让我们添加您已经弄清楚的 sed 指令,-e1,36d

$ cat ./sample_or_2day | tr -s ' ' '\n' | sed -n -e1,36d -e'/^1NAME$/'"{$next7;$next7}"
66.0000000E+00
130.0000000E+00

您可能还希望 bash 为您构造 sed 命令行:例如,命令

sed -n -e{7..29..7}p

将被 shell 扩展为

sed -n -e7p -e14p -e21p -e28p

如您所知,这意味着 sed 将只打印那些输入行。您可能还想了解 bash 中的 for 循环,它有两种不同的风格,例如:

for var in word1 word2 word3 ...; do ... ; done
for (( i=0; i<10; i++ )); do ...; done

现在,我不清楚您想如何管理输出文件。我提供了一个 bash 版本的脚本(为 GRID 提供了一个值列表,而不仅仅是一个),它显示了 bash 中另一种可能的大括号扩展。

#!/bin/bash
FILE=./sample_or_2day
for GRID in 23729 23755 23768; do
cat "$FILE" | tr -s ' ' '\n' | sed -n -e{28,41}p >> "./out_$GRID"
done

关于linux - 使用 bash 脚本根据给定条件使用 sed 提取位置特定记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48814328/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com