如何通过一次 sed 调用仅打印第 n 个替换?

如何通过一次 sed 调用仅打印第 n 个替换?

我有这个,其中几乎做我想做的事

git show-branch --current 62cba3e2b3ba8e1115bceba0179fea6c569d9274 \
  | sed --quiet --regexp-extended 's/^.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/\1 \2/p' \
  | sed --quiet 2p #combine this into the previous sed to avoid another pipe/fork

和输出

B-47120 java-11-take2

git show-branch正在输出这个

! [62cba3e2b3ba8e1115bceba0179fea6c569d9274] B-48141 remove env prefix
 * [ccushing/B-47120-java-10-take1] B-48141 remove env prefix
--
 * [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
+* [62cba3e2b3ba8e1115bceba0179fea6c569d9274] B-48141 remove env prefix

您会注意到 已sed通过管道传输到sed,这是因为我只想要第二行。我还没有找到将2p和 表达式组合成单个命令的方法。我尝试过各种各样的事情。我收到这样的错误

sed: can't read 2p: No such file or directory
sed: can't read s/^.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/\1 \2/p: No such file or directory

我在适用于 Windows 的 git,并且仅限于附带的工具。

答案1

Sed 一次将每一行读入模式空间。保留空间是一个附加槽,最初是空的,仅在明确命令时才会填充。

要仅打印第二个替换的匹配项,

sed -nE '/.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/{s//\1\2/;x;/./{x;p;q}}'
/pattern/{        # If the line matches the pattern
  s//replacement/ # Substitute the pattern by the replacement¹
  x               # Swap hold space and pattern space
  /./{            # If the pattern space is not empty, then
    x             # Swap hold space and pattern space
    p             # Print the line
    q             # Quit
  }
}

仅打印n第 次替换的比赛(此处n=3),

sed -nE '/pattern/{s//replacement/;H;x;/(.*\n){3}/{s///p;q};x}'
/pattern/{        # If the line matches the pattern
  s//replacement/ # Substitute the pattern by the replacement¹
  H               # Append a newline and the pattern space to the hold space
  x               # Swap hold space and pattern space
  /(.*\n){3}/{    # If the pattern space contains 3 newline characters²
    s///p         # Delete all up to the last newline¹
    q             # Quit
  }
  x               # Swap hold space and pattern space
}

1:空模式与上次使用的模式相同。 2:如果不使用该标志,
则转义括号和大括号(即)。\(.*\n\)\{3\}-E

答案2

如果我们将 sed 表达式放在一个变量中(没有最后一个p):

subs='s/^.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/\1 \2/'

并且,还将git-branch输出放入另一个变量中:

outout='! [62cba3e2b3ba8e1115bceba0179fea6c569d9274] B-48141 remove env prefix
 * [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
--
 * [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
+* [62cba3e2b3ba8e1115bceba0179fea6c569d9274] B-48141 remove env prefix'

我们可以将您的命令减少为(假设是 GNU sed):

printf '%s\n' "$outout" | sed -nE "${subs}p"

现在,更改pto;T;2p将执行您要求执行的操作(用于;T;2{s/-/ /2g;p}替换破折号):

$ printf '%s\n' "$outout" | sed -nE "${subs};T;2p"
B-47120 java-11-take2

请注意,数字 2 是对输入的第二行进行寻址,而不是第二个正则表达式匹配。

如果需要计算匹配行数,则需要使用 awk 或 perl,或两次调用 sed (您已经弄清楚了)。

相关内容