基于bash中的反向引用将字符串替换为另一个字符串

时间:2015-11-04 07:12:38

标签: regex linux bash sed

我正在尝试转换预定义字符串%c#,其中#可以是另一个字符串的某个数字。问题是,另一个字符串的长度必须截断为#个字符。

理想情况下,这些命令集可行:

FORMAT="%c10"
LAST_COMMIT="5189e42b14797b1e36ffb7fc5657c7eea08f1c0f"
echo $FORMAT | sed "s/%c\([0-9]\+\)/${LAST_COMMIT:0:\1}/g"

但很明显\ 1上有语法错误。您可以用数字替换它以查看我想要输出的内容。

我愿意使用除sed之外的其他程序来实现这一目标,但理想情况下它应该是大多数Linux安装本机的程序。

谢谢!

3 个答案:

答案 0 :(得分:0)

这是我的想法。

echo ${LAST_COMMIT} | head -c $(echo ${FORMAT} | sed -e 's/%c//')

使用sed获取号码,并使用head获得第一个字符。

<强> EDIT1

这可能会更好。

echo ${LAST_COMMIT} | head -c $(echo ${FORMAT} | sed -e 's/%c\([0-9]\+\)/\1/')

<强> EDIT2

我制作剧本因为它太难理解了。请试试这个。

$ cat sample.sh

#!/bin/bash

FORMAT="%b-%t-%c10-%c5"
LAST_COMMIT="5189e42b14797b1e36ffb7fc5657c7eea08f1c0f"

## List numbers
lengths=$(echo ${FORMAT} | sed -e "s/%[^c]//g" -e "s/-//g" -e "s/%c/ /g")

## Substitute %cXX to first XX characters of LAST_COMMIT
for n in ${lengths}
do
  to_str=$(echo ${LAST_COMMIT:0:${n}})
  FORMAT=$(echo ${FORMAT} | sed "s/%c${length}/${to_str}/")
done

## Print result
echo ${FORMAT}

结果就是这样。

$ ./sample.sh
%b-%t-5189e42b1410-5189e5

这也是一行命令(内容相同但太长而且太难)

for n in $(echo ${FORMAT} | sed -e "s/%[^c]//g" -e "s/-//g" -e "s/%c/ /g"); do to_str=$(echo ${LAST_COMMIT:0:${n}}); FORMAT=$(echo ${FORMAT} | sed "s/%c${length}/${to_str}/"); done; echo ${FORMAT}

答案 1 :(得分:0)

length=$(echo $FORMAT | sed "s/%c\([0-9]\+\)/\1/g")
echo "${LAST_COMMIT:0:$length}"

答案 2 :(得分:0)

$LAST_COMMIT的值在sed运行之前进行插值,因此没有后向引用来引用。 GNU /e中有一个sed扩展名可以支持这样的内容,但我只是使用功能稍强的工具。

perl -e '$fmt = shift; $fmt=~ s/%c(\d+)/%.$1s/g; printf("$fmt\n", @ARGV)' '%c10' "$LAST_COMMIT"

当然,如果您可以放弃自己的ad-hoc格式字符串说明符,并完全切换到printf兼容的格式字符串,只需直接使用printf shell命令。 / p>