就我而言,我需要立即编辑一大堆 CMakeLists.txt - 但我认为这个问题可以概括。问题是:
- 哪种工具更适合这项工作?
- 我将如何实现所需的输出?
[Optional:]
- 有没有办法清空/擦除 sed 中的保留空间?
- 有没有办法在保留空间中添加或追加行?
两个 target_include_directories 调用可能有也可能没有相同的参数。
问题陈述:
在 和的范围内target_include_directories(
,首先)
收集所有包含缩进的行windows
(缩进 4 个空格)并将它们放在 之前)
。
现在,$<$<PLATFORM_ID:Windows>:
在包含 的行块之前插入正确的缩进(在上面定义的范围内),并在包含 的行块之后windows
追加包含缩进的一行。>
windows
还要确保包含每个块的参数的最后一行没有分号,而其他所有行都有。
迄今为止所做的研究:
下面的行收集包含窗口的行并将它们放在正确的位置,但没有缩进,也没有装饰。
sed ':j;/^$/h;/target_include_directories(/,/)/{/windows/{H;d};/)/{H;x;D;G;bj}}' CMakeLists.txt
样本数据:
...
##############
# Unique Big Block
##############
if(some_condition)
target_include_directories(foo Public
arg0floor;
arg1windowsred;
arg2chairs;
arg3bluewindows;
arg4tables;
...
argnwalls
)
elseif(some_other_condition)
target_include_directories(foo Public
arg0yeast;
arg1windowsbroken;
arg2barley;
arg3wavywindows;
arg4water;
...
argnsugar
)
endif()
##############
# Other Unique Big Block
##############
...
预期输出:
...
##############
# Unique Big Block
##############
if(some_condition)
target_include_directories(foo Public
arg0floor;
arg2chairs;
arg4tables;
...
argnwalls
$<$<PLATFORM_ID:Windows>:
arg1windowsred;
arg3bluewindows;
...
argkwindowsblack
>
)
elseif(some_other_condition)
target_include_directories(foo Public
arg0yeast;
arg2barley;
arg4water;
...
argnsugar
$<$<PLATFORM_ID:Windows>:
arg1windowsbroken;
arg3wavywindows;
...
argkmilkywindows
>
)
endif()
##############
# Other Unique Big Block
##############
...
答案1
我同意博多、AWK 或 Perl 更适合。我在这里使用 AWK,它足以完成这项工作。
以下是涉及的步骤。 AWK 是一种基于记录的模式匹配语言;默认情况下,一条记录是一行。所以在这种情况下,我会编写一个程序
- 查找
target_include_directories
,并注意我们现在位于包含块中; - 当在包含块中时,匹配包含“windows”的行,并将它们存储在数组中而不是输出它们;其他行按原样输出;
- 在包含块中时,查找右括号;找到后,输出存储的行以及平台前缀。
处理行尾分号涉及一些额外的处理;处理这个问题的一种方法是存储不带前导空格和尾随分号的包含行,并根据上下文对它们进行修饰。
一种实现方式如下:
#!/usr/bin/gawk -f # Note the start of a block, clear the memorised includes, # print the current line and skip to the next one /target_include_directories/ { in_include_block = 1 delete includes print next } # In a block, if we match "windows", memorise the value without its semi-colon in_include_block && /windows/ { includes[length(includes)] = gensub(";", "", "g", $1) } # In an include block, when we reach the end, output the memorised includes in_include_block && /)/ { if (length(includes) > 0) { printf " $<$<PLATFORM_ID:Windows>:" for (i = 0; i < length(includes); i++) { if (i > 0) { printf ";" } printf "\n %s", includes[i] } print "\n >" } in_include_block = 0 } # In an include block, if we don't match, print the line in_include_block && !/windows/ # Outside include blocks, print !in_include_block
- 查找