【问题标题】:Make SED command work for any variable使 SED 命令适用于任何变量
【发布时间】:2013-11-27 14:37:57
【问题描述】:

deploy.sh

USERNAME="Tom"
PASSWORD="abc123"
FILE="config.conf"
sed -i "s/\PLACEHOLDER_USERNAME/$USERNAME/g" $FILE
sed -i "s/\PLACEHOLDER_PASSWORD/$PASSWORD/g" $FILE

config.conf

deloy="PLACEHOLDER_USERNAME"
pass="PLACEHOLDER_PASSWORD"

此文件将我在部署中定义的变量放入我的配置文件中。我无法获取文件,所以我想以这种方式放置我的变量。

问题

我想要一个通用的命令,以便使用某种 while 循环而不是每个变量都需要一个命令来处理 所有占位符变量。这意味着文件中以 placeholder_ 开头的任何术语都将尝试替换为已在 deploy.sh 中定义的变量的值

所有变量都应该设置并且不能为空。我想如果它找不到好的变量,是否有能力打印警告,但这不是强制性的。

【问题讨论】:

标签: linux bash shell sed debian


【解决方案1】:

基本上就是用shell代码写一个sed脚本,然后用sed -i .bak -f sed.script config.conf来应用:

trap "rm -f sed.script; exit 1" 0 1 2 3 13 15

for var in USERNAME PASSWORD
do
    echo "s/PLACEHOLDER_$var/${!var}/"
done > sed.script

sed -i .bak -f sed.script config.conf

rm -f sed.script
trap 0

这里的主要“技巧”是:

  1. 知道${!var} 扩展为$var 命名的变量的值,并且
  2. 知道sed 将通过-f sed.script 获取一个充满命令的脚本,并且
  3. 知道如何使用trap 来确保清理临时文件。

您也可以使用sed -e "s/.../.../" -e "s/.../.../" -i .bak config.conf,但我认为脚本文件更容易,特别是如果您有两个以上的值要替换。如果您想沿着这条路线走,请使用bash 数组来保存sed 的参数。更仔细的脚本会在脚本文件名中至少使用$$,或者使用mktemp 创建临时文件。


修改后的答案

问题是,虽然更接近通用,但它仍然不是通用的,因为我必须手动输入我想要更改的变量。难道不是更像“对于每个占位符_,在deploy.sh中找到变量并添加该变量,以便它可以用于任意数量的变量。

所以,找出配置文件中的变量是什么,然后应用上一个答案的技术来解决这个问题:

trap "rm -f $tmp; exit 1" 0 1 2 3 13 15

for file in "$@"
do

    for var in $(sed 's/.*PLACEHOLDER_\([A-Z0-9_]*\).*/\1/' "$file")
    do
        value="${!var}"
        [ -z "$value" ] && { echo "$0: variable $var not set for $file" >&2; exit 1; }
        echo "s/PLACEHOLDER_$var/$value/"
    done > $tmp

    sed -i .bak -f $tmp "$file"

    rm -f $tmp

done

trap 0

此代码仍从环境中提取值。如果您想从 shell 脚本中提取设置,您需要阐明需要什么,但这是可以做到的——脚本必须有足够的自我意识才能找到它的来源,以便它可以搜索名称。但是基础知识在这个答案中;剩下的就是修修补补,直到它满足你的需要。

【讨论】:

  • 非常感谢您的详细回答。问题是,虽然更接近通用,但它仍然不是通用的,因为我必须手动输入我想要更改的变量。难道不是更像“对于每个占位符_,在 deploy.sh 中找到变量并添加该变量,这样它就可以适用于任意数量的变量。
  • 请使用您评论中的额外信息更新问题。您的环境是否总是设置所有变量?如果未设置必需的变量,脚本应该做什么?变量可以为空吗?
  • 已按您的要求更新,感谢您的帮助。
【解决方案2】:
#!/bin/ksh
TemplateFile=$1
SourceData=$2

(sed 's/.*/#V0r:PLACEHOLDER_&:r0V#/' ${SourceData}; cat ${TemplateFile}) | sed -n "

s/$/²/
H

$  {
   x
   s/^\(\n *\)*//
# also reset t flag
   t varxs

:varxs
   s/^#V0r:\([a-zA-Z0-9_]\{1,\}\)=\([^²]*\):r0V#²\(\n.*\)\"\1\"/#V0r:\1=\2:r0V#²\3\2/
   t varxs

# clean the line when no more occurance in text
   s/^[^²]*:r0V#²\n//

# and next
   t varxs


# clean the  marker
   s/²\(\n\)/\1/g
   s/²$//

# display the result
   p
   }
"

这样调用:YourScript.ksh YourTemplateFile YourDataSourceFile 其中:

  • YourTemplateFile 是包含具有通用值的结构的文件,例如 deloy="PLACEHOLDER_USERNAME"
  • YourDataSourceFile 是包含所有对等点的文件 Generic value = specific value like USERNAME="Tom"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-17
    • 2012-06-24
    • 2022-01-08
    • 2022-10-07
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多