如何用sed实现类似Awk $0的行复用,完成指定文本格式转换?
解决方案:单行命令实现字符串转换与拼接
用Sed单行命令完成
利用Sed的保留空间(hold space)留存原始行内容,先处理大小写转换,再拼接原始内容和转换结果:
sed -r 'h; s/(^|_)([a-z])/\1\U\2/g; s/^/'\''/; s/$/'\'';/; x; s/^/'\''/; s/$/'\'':/; G; s/\n//' /tmp/list
命令细节拆解:
h:把当前行复制到保留空间,保存原始字符串s/(^|_)([a-z])/\1\U\2/g:将行首或下划线后的小写字母转为大写(替换原命令的\b为^,更精准匹配行首场景)s/^/'/; s/$/';/:为转换后的字符串添加前后单引号和结尾分号x:交换模式空间与保留空间,此时模式空间是原始行,保留空间是处理好的转换结果s/^/'/; s/$/':/:为原始字符串添加前后单引号和结尾冒号G:把保留空间的内容追加到模式空间末尾(中间带换行符)s/\n//:删除中间的换行符,完成最终拼接输出
用Awk实现更易读
如果觉得Sed命令偏晦涩,Awk的写法更直观,利用GNU Awk的gensub直接处理大小写转换:
awk '{conv = gensub(/(^|_)([a-z])/, "\\1\\U\\2", "g", $0); printf("'\''%s'\'' : '\''%s'\'';\n", $0, conv)}' /tmp/list
若使用不支持gensub的Awk版本,可通过拆分字符串实现:
awk '{ orig = $0 n = split(orig, parts, "_") conv = "" for (i=1; i<=n; i++) { conv = conv (i>1 ? "_" : "") toupper(substr(parts[i],1,1)) substr(parts[i],2) } printf("'\''%s'\'' : '\''%s'\'';\n", orig, conv) }' /tmp/list
关于你当前的实现
你用while read循环嵌套Sed的方式虽然能实现需求,但每次循环都会启动一个新的Sed进程,在处理大量数据时效率较低。上面的Sed和Awk方案均为单进程处理,更简洁高效。
内容的提问来源于stack exchange,提问作者darxmurf
相关产品推荐
相关产品推荐

