如何仅用sed、awk等shell命令按行块内machine值修改对应request字段
问题描述
现有一个包含多段行块的文件,示例内容如下:
line1 line1 ----- machine:chrome purpose: language:v2 request:v3 additional: v4 os:v4 ----- machine:firefox purpose: language:v2 request:v6 os:v4 ----- machine:helper purpose: language:v2 request:v8 os:v4 ----- another line
这些行块包含的元素不一定完全相同,但都统一以machine字段开头、os字段结尾。需求是仅使用shell命令实现:逐段解析每个从machine到os的行块内machine开头行的取值,用该取值执行对应shell命令,再将命令输出填入同块的request字段中,是否可以仅使用sed和awk实现该需求?
预期输出效果
line1 line1 ----- machine:chrome purpose: language:v2 request:[output of result of ps -ef chrome | awk '{print $2}'] additional: v4 os:v4 ----- machine:firefox purpose: language:v2 request:[output of result of ps -ef firefox | awk '{print $2}'] os:v4 ----- machine:helper purpose: language:v2 request:[output of result of ps -ef helper | awk '{print $2}'] os:v4 ----- another line
已尝试方案
用户尝试单独使用sed编写了如下命令:
gsed -r '/machine/,/os/ {/machine/ {s/.*?:\s*([^\s]+)/ps -ef | grep \1\n/e}; /request/ {s/.*?:\s*([^\s]+)//}}' filename
该命令无法正常达到预期效果,但可以执行ps -ef | grep [machinename]并将结果存储在缓冲区,想知道能否将缓冲区的值用于request字段的替换,以及具体实现方法。
解决方案
可以实现,更推荐使用awk完成,逻辑清晰不需要依赖GNU sed的非标准扩展,实现代码如下:
awk ' BEGIN { FS=":" } /^-----$/ { in_block=0; print; next } /^machine:/ { in_block=1 # 提取machine值,去除首尾空白 machine_val=$2 gsub(/^[ \t]+|[ \t]+$/, "", machine_val) # 执行命令获取对应PID,可根据实际需求调整命令内容 cmd = "ps -ef | grep " machine_val " | grep -v grep | awk \'{print $2}\' | head -n1" cmd | getline req_val close(cmd) print $0 next } # 块内匹配到request行直接替换输出 in_block && /^request:/ { print "request:" req_val next } # 其他行原样输出 { print } ' your_file
如果一定要用GNU sed实现也可以通过hold空间暂存命令结果,但逻辑可读性远低于awk方案。你之前写的sed命令问题出在e标志会直接把替换后的内容作为命令执行,将原machine行直接替换为命令输出,不符合保留原machine行的要求。
内容的提问来源于stack exchange,提问作者amadain
相关产品推荐
相关产品推荐

