Arrays 在文件的某些行上添加文本,添加的文本取决于从该行获取子字符串的命令的输出

Arrays 在文件的某些行上添加文本,添加的文本取决于从该行获取子字符串的命令的输出,arrays,bash,awk,sed,Arrays,Bash,Awk,Sed,我正在尝试制作一个shell脚本,以获取一个输入文件(数千行)并生成一个输出文件,该输出文件除了在某些行上会添加文本外,其他都是相同的。将文本添加到行(中间)时,添加的确切文本将取决于行上的子字符串。子字符串和添加的文本之间的关联是复杂的,并且来自我可以在shell中调用的外部程序。我没有这个转换器程序的源代码,也无法控制映射是如何完成的 为了进一步解释 我有一个通用格式的输入文件: Blah Blah Unimportant Something Something FIELD_INFO(fie

我正在尝试制作一个shell脚本,以获取一个输入文件(数千行)并生成一个输出文件,该输出文件除了在某些行上会添加文本外,其他都是相同的。将文本添加到行(中间)时,添加的确切文本将取决于行上的子字符串。子字符串和添加的文本之间的关联是复杂的,并且来自我可以在shell中调用的外部程序。我没有这个转换器程序的源代码,也无法控制映射是如何完成的

为了进一步解释

我有一个通用格式的输入文件:

Blah Blah Unimportant
Something Something
FIELD_INFO(field_name_1, output_1),
  FIELD_INFO(field_name_2, output_2),
Yadda Yadda
需要复制整个文件,并添加文本,但对我来说唯一重要的部分是字段名(例如字段名1、字段名2)。我有一个名为“converter”的命令行程序,它可以获取字段名文件并输出相应操作的列表。转换器不能直接对输入文件进行操作。转换器的输入只需要字段名,转换器的输出有我不需要的额外信息:

converter_field_name_1 "action1" /* Use this action for field_name_1 */
converter_field_name_2 "action2" /* use this action for field_name_2 */
需要创建第二个文件,如下所示:

Blah Blah Unimportant
Something Something
FIELD_INFO(field_name_1, action1, output_1),
  FIELD_INFO(filed_name_2, action2, output_2),
Yadda Yadda
Blah Blah Unimportant
Something Something
FIELD_INFO(field_name_1, ,  output_1),
  FIELD_INFO(field_name_2, ,  output_2),
Yadda Yadda

以下是我正在编写的脚本,但我遇到了一个(或两个)障碍:

我的实际脚本中有分散的调试语句,我知道字段数组、操作数组和映射器数组都是正确创建的。但是我使用sed中的group-capture子字符串作为映射器数组的索引的想法不起作用,因为我现在知道sed在子shell中运行之前会展开变量,因此映射器[]数组不会将子字符串作为索引

我该怎么做呢?此脚本只能使用一次,但手工添加操作字符串太耗时且容易出错。我想想出一个办法来实现这一点,但我不知道我是接近还是完全走错了路。

为什么不试试

sed -n -e 's/^[ ]*FIELD_INFO(\(.*\),.*,/\1/p' -- input_file > script_field_names.txt
printf '/^[ ]*FIELD_INFO(%s,/ s/(\\(.[^,]*\\), \\(.[^)]*\\))/(\\1, %s, \\2)/\n' \
    $(converter -f script_field_names.txt | cut -d'"' -f 2 |
      paste -- script_field_names.txt -) |
    sed -f /dev/stdin -- input_file
在哪里

  • paste
    发出字段(来自文件)和操作(来自标准输入法)的映射
  • printf
    发出由
    sed
    从stdin读取的脚本
  • 每个脚本行变为:
    /^[]*字段信息(fieldnameN,/s/(\([^,]*\),\([^)]*\)/(\1,actionN,\2)/
sed-e“s/FIELD\u INFO(\(.*),\(.*),\)/FIELD\u INFO(\1,${mapper[\1],\2}/”<${filename}
[...] 我现在知道sed在子shell中运行之前会展开变量,因此mapper[]数组不会将子字符串视为索引

很好地识别了问题。此外,非贪婪量词
*?
不适用于
sed
${mapper[\1],\2}
可能应该是
${mapper[\1]}、\2

如果你想保持目前的方法,我有两个选择

  • 在bash中逐行进行替换,或者创建一个巨大的sed命令字符串,列出每行的操作,或者在循环中为每行执行sed,同时动态创建命令字符串
  • 不要使用数组
    映射器
    ,而是创建一个文件,列出要按文件顺序插入的操作。然后使用GNU sed的
    R filename
    命令。此命令插入
    filename
    中的下一行。您可以使用此命令在每次遇到文件时插入正确的操作。但是,换行符是iN也被插入。所以你必须摆弄等待空间等等,以便在之后移除这些换行符
这两个选项都不是很好。因此我要切换到
awk
插入操作:


请使用两个样本输入(
字段名\u 1
/
字段名\u 2
)的
转换器的准确输出更新问题…没有注释,没有额外的字符/符号;它是否真的输出字符串
convert\u field\u name\u 1
field\u name\u 1
?是否
action1
用双引号括起来?是否
action1
包含空格?是否所有感兴趣的行都包含文本字符串
field\u INFO
您有一个要搜索的字符串变量列表的真实数据文件?@markp fuso转换器的输出如图所示,包括注释和前置的“converter_”.Action总是用双引号括起来。Action可以包含大多数特殊字符,但不能包含空格、逗号、反勾号、at符号、美元符号、单引号或双引号。所有感兴趣的行都包含字段\信息,并且没有任何行包含不感兴趣的字段\信息。谢谢您的提问。谢谢您提供的详细信息我给出了答案,看了看我能做什么和应该做什么。我将你的答案标记为接受答案,因为事实上,我已经切换到使用awk进行插入。我认为awk可能是正确的方法,但我正在努力理解语法或不知道从何开始。一位用户在5分钟内对我的问题发表了评论我的帖子带有一个awk建议,在他们删除评论之前,我能够从中吸取教训。我的最终脚本看起来有点像你的建议,只是更长,更不优雅。:-)谢谢你的回答。如果我考虑过我可以为sed生成自定义命令并通过stdin将它们发送到脚本中的sed这一事实,我可能会这样做。我觉得很酷。最后我确实使用了awk进行了插入,这对我来说很好,因为我了解了更多关于awk的知识,但我也喜欢你的方法。
sed -n -e 's/^[ ]*FIELD_INFO(\(.*\),.*,/\1/p' -- input_file > script_field_names.txt
printf '/^[ ]*FIELD_INFO(%s,/ s/(\\(.[^,]*\\), \\(.[^)]*\\))/(\\1, %s, \\2)/\n' \
    $(converter -f script_field_names.txt | cut -d'"' -f 2 |
      paste -- script_field_names.txt -) |
    sed -f /dev/stdin -- input_file
sed -En 's/^\s*FIELD_INFO\(([^,]*).*/\1/p' "$filename" > fields
converter -f fields | cut -d\" -f2 > actions
awk '/^\s*FIELD_INFO\(/ {getline a < "actions"; sub(",", ", " a ",")} 1' "$filename"
grep -Po '^\s*FIELD_INFO\(\K[^,]*' "$filename" > fields