【问题标题】:Shell execute grep command within sed replacement not as expectedShell 在 sed 替换中执行 grep 命令不符合预期
【发布时间】:2021-03-15 22:32:23
【问题描述】:

我正在为 Kubernetes 编写一些部署脚本,并希望使用 sed 执行单个命令来替换 yaml 文件中的一些“模板变量”。

我有以下(例如,缩短的 yaml 文件)输入文件,我想在其中进行替换:
输入.txt

CONTAINER_ADDITIONAL
spec:
  selector:
    app: CONTAINER_NAME
  type: NodePort
  ports:
    - protocol: TCP
      port: EXPOSED_PORT

另外,我有以下 Dockerfile,我想从中获取 EXPOSE 端口号以插入到 EXPOSED_PORT
Dockerfile

FROM node:latest

EXPOSE 3000
WORKDIR /app

我现在尝试使用不同的方法将端口号 3000(来自 Dockerfile)插入到 EXPOSED_PORT
CONTAINER_NAMECONTAINER_ADDITIONAL 正在工作,它们位于示例文件中,以便使用以下命令完成)。

以下命令可以直接在shell中执行并给出想要的结果(3000):
cat Dockerfile | grep EXPOSE | cut -d" " -f2 -> 可能还有\n
cat Dockerfile | grep EXPOSE | cut -d" " -f2 | tr -d "\n" -> 前面提到过\n 已移除
grep EXPOSE Dockerfile | cut -d" " -f2 -> 带有 \n
grep EXPOSE Dockerfile | cut -d" " -f2 | tr -d "\n" -> 不带有 \n
grep EXPOSE Dockerfile | awk '{print $2}' -> 带有 \n,使用单引号 - 不是一个选项?grep EXPOSE Dockerfile|tr -d -c 0-9 -> 不带\n,不首选(当存在多个端口号由空格分隔的情况时)
grep -Po "(?<=^EXPOSE )\w*$" Dockerfile -> 带\n,不首选(多个端口号) grep -Po "(?<=^EXPOSE )\w*$" Dockerfile | tr -d "\n" -> 没有\n

但是:

sed -e 's@CONTAINER_NAME@some-container-name@g;s@CONTAINER_ADDITIONAL@cat some_config.txt@e;s@EXPOSED_PORT@grep EXPOSE Dockerfile | cut -d" " -f2 | tr -d "\n"@e' input.txt

不适用于EXPOSED_PORT。其他两个变量 CONTAINER_NAMECONTAINER_ADDITIONAL 起作用(猫被执行,some_config.txt 的内容被放入其中)

无论上面提到的哪个命令在 shell 中直接运行并给出正确的结果,在 sed 中执行时它们都不起作用(awk 肯定不会,因为单引号)。

我得到的输出是:

inserted_content_of: some_config.txt
some_more_inserted_content_from: some_config.txt
spec:
  selector:
    app: some-container-name
  type: NodePort
  ports:
    - protocol: TCP
sh: 1: port:: not found

我想要的预期输出:

inserted_content_of: some_config.txt
some_more_inserted_content_from: some_config.txt
spec:
  selector:
    app: some-container-name
  type: NodePort
  ports:
    - protocol: TCP
      port: 3000

我的 sed 命令有什么问题吗?
有什么问题可以解释一下吗?
我该如何解决这个问题?

【问题讨论】:

  • sed -e "s@CONTAINER_NAME@some-container-name@g;s@CONTAINER_ADDITIONAL@$(cat some_config.txt)@e;s@EXPOSED_PORT@$(grep EXPOSE 输入。 txt | cut -d" " -f2 | tr -d \"\n\")@e" input.txt?
  • sed: -e expression #1, char 78: unterminated `s' command 甚至在尝试恢复为 sed 的单引号并撤消双引号的转义时。

标签: linux bash shell sed grep


【解决方案1】:

我想,那

grep EXPOSE input.txt | cut -d" " -f2

是获取端口号的好方法(\n 在其他命令中使用时不会附加)。也许您应该在下一步之前先保存它。

portnumber=$(grep EXPOSE input.txt | cut -d" " -f2)
echo "The portnumber will be [${portnumber}]."

我会将您的grep 命令替换为echo "4444",显示您的嵌套命令存在问题。
使用@e,您要求sed 在处理s@EXPOSED_PORT@echo "4444"@ 后执行结果字符串。带有 EXPOSED_PORT 的行是

port: EXPOSED_PORT

所以sed 正在尝试执行port echo "4444",并抱怨命令port
当你想使用@e 时,你应该使用类似

sed -r 's@(.*)(EXPOSED_PORT)(.*)@echo "\1$(echo "4444")\3"@e' input.txt

你认为这很容易吗?试试这样:

sed 's@EXPOSED_PORT@'${portnumber}'@' input.txt
# or when you really want to squeeze your command into this line
sed 's@EXPOSED_PORT@'$(echo "4444")'@' input.txt

或者看awk

awk -v port=${portnumber} '/EXPOSED_PORT/ {$2=port} 1' input.txt
# or nested
awk -v port=$(echo "4444") '/EXPOSED_PORT/ {$2=port} 1' input.txt

【讨论】:

    【解决方案2】:

    问题是您在更改端口时并没有更改整条线路,而只是更改了线路的一部分。因为前面的“端口:”已被留下,sed 尝试与 grep 命令一起执行此命令,因此出现错误。为了克服这一点,搜索并替换整行等等:

    sed -e 's@CONTAINER_NAME@some-container-name@g;s@CONTAINER_ADDITIONAL@cat some_config.txt@e;s@^.*EXPOSED_PORT@echo "      port: $(grep EXPOSE input.txt | cut -d" " -f2 | tr -d "\n")"@e' input.txt
    

    回显前导端口:连同扩展的 grep 命令。

    【讨论】:

    • 伟大而简短的解释,非常感谢。您的命令工作得很好,但是在port: 之前接受的关于间距的答案的灵活性更大
    • 不用担心。一个赞将不胜感激;@)
    • 我赞成/喜欢,你的回答,但因为我的帐户是相对新的,它不显示它,但它被计数:)
    猜你喜欢
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 2010-11-29
    • 2014-09-22
    • 2018-09-16
    相关资源
    最近更新 更多