【问题标题】:Using value inside a variable without expanding在变量中使用值而不扩展
【发布时间】:2019-09-18 02:42:48
【问题描述】:

我正在尝试使用 sed 命令查找和替换特定的文本内容,并通过 shell 脚本运行它。

以下是我正在使用的示例脚本:

fp=/asd/filename.txt

fd="sed -i -E 's ($2).* $2:$3 g' ${fp}"
eval $fd

并通过传递参数执行相同的操作:

./test.sh update asd asdfgh

但如果参数字符串包含 $ ,它会破坏命令并替换为错误的值,例如

./test.sh update asd $apr1$HnIF6bOt$9m3NzAwr.aG1Yp.t.bpIS1.

如何确保变量内的值不会因为$ 而被扩展?

更新

sh 文件 test.sh

set -xv

fp="/asd/filename.txt"

sed -iE "s/(${2//'$'/'\$'}).*/${2//'$'/'\$'}:${3//'$'/'\$'}/g" "$fp"

文本文件filename.txt

hello:world

输出

1) ./test.sh 更新你好世界

sed -iE "s/(${2//'$'/'\$'}).*/${2//'$'/'\$'}:${3//'$'/'\$'}/g" "$fp"
++ sed -iE 's/(hello).*/hello:WORLD/g' /asd/filename.txt

2) ./test.sh 更新你好'$apr1$hosgaxyv$D0KXp5dCyZ2BUYCS9BmHu1'

sed -iE "s/(${2//'$'/'\$'}).*/${2//'$'/'\$'}:${3//'$'/'\$'}/g" "$fp"
++ sed -iE 's/(hello).*/hello:'\''$'\''apr1'\''$'\''hosgaxyv'\''$'\''D0KXp5dCyZ2BUYCS9BmHu1/g' /asd/filename.txt

在这两种情况下,它都不会替换内容

【问题讨论】:

  • 你为什么需要eval
  • @BenjaminW。我认为这是执行动态命令的方式。到目前为止还没有使用脚本。而且我什至不知道它的基础知识。所以我全神贯注
  • filename.txt 是什么样的,为什么它不只是一个您可以获取的函数定义文件,以便您可以调用适当的函数而不是使用eval?跨度>
  • @chepner 这是带有用户名和加密密码的 htpassword 文件
  • 对不起,我看错了作业;我以为你试图将sedresult 作为命令执行。

标签: bash sed sh


【解决方案1】:

这里根本不需要eval

fp=/asd/filename.txt
sed -i -E "s/(${2//'$'/'\$'}).*/\1:${3//'$'/'\$'}/g" "$fp"
  • 整个 sed 命令用双引号括起来,以便变量可以展开。
  • 我已将 s 分隔符的空白替换为 /(在示例中并不重要)。
  • 我使用\1 来引用第一个捕获组,而不是在替换中重复变量。
  • 最重要的是,我使用了${2//'$'/'\$'} 而不是$2$3 也类似)。这会将每个$ 符号转义为\$;这是必需的,因为双引号,或者 $ 在 sed 看到它们之前就被 shell 吃掉了。

当您调用脚本时,您必须转义输入中的任何 $,否则 shell 会尝试将它们扩展为变量名:

./test.sh update asd '$apr1$HnIF6bOt$9m3NzAwr.aG1Yp.t.bpIS1.'

【讨论】:

  • 但是当我用 $apr1$HnIF6bOt$9m3NzAwr.aG1Yp.t.bpIS1 触发相同的。作为第三个参数,它用最后一个'$'之后的字符串替换它。即'm3NzAwr.aG1Yp.t.bpIS1'
  • 我使用空白作为 s 分隔符,因为我的字符串可以在值中包含“/”。
  • @Andromeda 调用命令时还需要引用$,我添加了一个用法示例。
  • 它对我不起作用...我什至尝试使用没有任何 $.. 的输入。它没有替换内容
  • @Andromeda 你是不是碰巧在 macOS 上?
【解决方案2】:

将作为文件名的命令行参数放在单引号中:

./test.sh update 'asd' '$apr1$HnIF6bOt$9m3NzAwr.aG1Yp.t.bpIS1'

【讨论】:

  • 愚蠢的 eval` 可能会阻止这个工作,所以这还不够。
【解决方案3】:

如果有空格和特殊的shell字符,必须用引号保护所有脚本参数,如果是美元$-Ei而不是-iE,则最好先将其丢弃以进行测试,以后可以添加它如果真的确定
我承认我不会理解你的正则表达式,所以让我们了解一下解决方案的要点,不需要评估;

fp=/asd/filename.txt

sed -Ei "s/($2).*/$2:$3/g" $fp

./test.sh update asd '\$apr1\$HnIF6bOt\$9m3NzAwr.aG1Yp.t.bpIS1.'

【讨论】:

    猜你喜欢
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2019-06-04
    • 2020-12-21
    • 2023-03-25
    相关资源
    最近更新 更多