【问题标题】:loop inside sed script doesn't terminatesed 脚本内的循环不会终止
【发布时间】:2016-11-21 06:23:46
【问题描述】:

假设我有一个这样的文件:

...
{
     ...
     cout<< "---at time:\t\t"<< sc_core::sc_time_stamp()<<"\n\n" << endl;
     ...
     cout<< "---at time:\t\t"<< sc_core::sc_time_stamp()<<"\n\n" << endl;
     ...
}
...
{
     ...
     if(strcmp(argv[1], "--io_freq1_Mhz") != 0)
     if(strcmp(argv[2], "--io_freq2_Mhz") != 0)
     ...
     if(strcmp(argv[11], "--bytes_per_word") != 0)
     ...
     if(strcmp(argv[23], "--mem_size_bytes") != 0)
     ...
}

我首先要做的是,使用 sed,加载包含该模式的所有行 “--富” 进入模式空间并只打印出括号内的部分,所以我使用命令:

sed -n -e 's/.*[^-]\(-\{2\}[^-].*\)"\(.*\)/\1/p' file

这正是我想要的,所以我得到了输出:

--io_freq1_Mhz
--io_freq2_Mhz
...
--bytes_per_word
...
--mem_size_bytes

接下来我想将所有行合并为一个,并用空格分隔内容。我可以使用命令替换来解决这个问题:

echo `sed -n -e 's/.*[^-]\(-\{2\}[^-].*\)"\(.*\)/\1/p' file`

这给了我:

--io_freq1_Mhz --io_freq2_Mhz --... --bytes_per_word --... --mem_size_bytes

接下来我想在参数之间插入一个数字,例如1,所以最终的结果应该是这样的:

--io_freq1_Mhz 1 --io_freq2_Mhz 1 --... 1 --bytes_per_word 1 --... 1 --mem_size_bytes 1

我几乎可以解决这个问题。我正在使用命令:

echo `sed -n -e 's/.*[^-]\(-\{2\}[^-].*\)"\(.*\)/\1/p' file` | sed -n -e ':start { s/\(--[^\ ]*\) -/\1 1 -/p; b start }' | sed -n -e 's/\(--.*[^\ ]\)/\1 1/p'

但我遇到了两个小问题。首先,在我跳回到我的开始标记之前,输出被传送到最后一个 sed 语句中,这意味着我得到了一个输出:

--io_freq1_Mhz 1 --io_freq2_Mhz --... --bytes_per_word --... --mem_size_bytes 1
--io_freq1_Mhz 1 --io_freq2_Mhz 1 --... --bytes_per_word --... --mem_size_bytes 1

等等。所以我的第一个问题是,如何避免每次将输出管道传输到我的最后一个 sed 语句中。我可以使用不同的 sed 选项/标志来实现这一点吗?

第二个问题是,命令不会终止。迭代以

结束
--io_freq1_Mhz 1 --io_freq2_Mhz 1 --... --bytes_per_word 1 --... --third_last_item 1 --second_last_item mem_size_bytes 1

可以看出,在倒数第二个项目后面没有附加“1”,另外整个命令也没有终止。我必须使用 Ctrl-C 终止它。

【问题讨论】:

  • 符号echo `sed … file` | sed … 很糟糕。你应该使用sed … file | sed …。您正在依次运行 3 个 sed 命令;应该减少到 1,几乎可以肯定,或者你应该改用 awk(或 Perl 或 Python)。
  • 欢迎来到 Stack Overflow。请注意,在这里说“谢谢”的首选方式是投票赞成好的问题和有用的答案(一旦你有足够的声誉这样做),并接受对你提出的任何问题最有帮助的答案(这也给出了你的声誉小幅提升)。请查看About 页面以及How do I ask questions here?What do I do when someone answers my question?

标签: regex sed


【解决方案1】:

对您的第一个命令稍作修改:

sed -n -e 's/.*[^-]\(-\{2\}[^-].*\)"\(.*\)/\1 1/p' file | tr '\n' ' '

提取名称后,在其后附加数字。 tr 命令将换行符转换为空格。您可以在sed 中完成所有操作;这将是繁琐的,仅此而已。


实际上,它并没有那么繁琐,但它需要一种不同的方式来看待这个过程。具体来说,您需要将匹配模式保存在保持空间中,然后在输入结束时将它们全部处理:

sed -n \
    -e '/.*[^-]\(-\{2\}[^-].*\)"\(.*\)/{ s//\1 1/; H; }' \
    -e '$ { x; s/\n/ /g; p; }' file 

} 字符前的分号对于 BSD (macOS) sed 是必需的,但对于 GNU sed 则不需要。第一个-e 选项查找与您的模式匹配的行,然后将替换命令应用于该行以仅保留--name 部分加上数字1,然后将该信息附加到换行符之后的保留空间。第二个-e 选项在最后一行起作用。它交换模式和保持空格,然后用空白替换每个换行符并打印结果,包括带有tr 的脚本用空白替换的尾随换行符。

输出(注意前导空格):

 --io_freq1_Mhz 1 --io_freq2_Mhz 1 --bytes_per_word 1 --mem_size_bytes 1

如果您不想要前导空白,请在打印前将其删除(在 p 之前添加 s/^ //;)。

【讨论】:

  • 谢谢,成功了。所以,我假设我以一种复杂的方式尝试了它;-)。至少我学到了一些东西......
  • @FloHe:查看更新——我的第一个解决方案使用两个命令,其中一个就足够了。
猜你喜欢
  • 2021-01-19
  • 1970-01-01
  • 2017-04-22
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 2018-10-02
相关资源
最近更新 更多