【问题标题】:Have sed operate on variable instead of standard input or a filesed 对变量而不是标准输入或文件进行操作
【发布时间】:2016-06-25 12:33:29
【问题描述】:

有很多问题询问如何在 sed 模式中使用变量,例如:sed "s/re/$VAR/" file,但我想对变量执行替换。到目前为止,我一直在使用echo 来做到这一点:

echo "$VAR" | sed 's/re/new/'

但是,虽然这可行,但它看起来很乱。在 bash 或 zsh 中是否有更简单/更优雅的方法?

【问题讨论】:

  • 如果需要是正则表达式,我觉得没有别的办法了。对于simple replacements(在bash)你可以做echo ${VAR/match/replace}
  • 我同意肖恩的观点,这并不混乱,因为这是要走的路。或者您可以使用特定的 shell 技巧(用于 bash 或 zsh)
  • @zmo,嗯?肖恩的建议(我同意这并不混乱)就是您所说的“特定于外壳的技巧”。 (手头的特定 PE 实际上根本不是 bash 和 zsh 特定的——相反,它们最初是 ksh 行为,至少可以追溯到 ksh88,bash 和 zsh 都兼容。值得注意的是, ksh88 早于 POSIX sh 标准的发布,因此即使 POSIX sh 标准没有包括 ksh 所做的所有 PE,它们的含义已经非常成熟)。

标签: regex shell variables sed


【解决方案1】:

如果不想使用sed,可以在参数内使用“parameter expansion”进行搜索替换;引用 Bash 手册:

 ${参数/模式/字符串} 

pattern 被扩展以产生一个模式,就像在文件名中一样 扩张。 Parameter 展开和 pattern 的最长匹配 其值被替换为 string.

如果pattern以/开头,则pattern的所有匹配项都会被替换 字符串。通常只替换第一场比赛。如果模式 以#开头,必须匹配展开值的开头 参数。如果 pattern 以% 开头,则必须匹配到最后 参数的扩展值。

如果 string 为 null,则 pattern 的匹配项将被删除,/ 后面的 pattern 可以省略。如果 参数 是 @ 或 *,则 替换操作应用于每个位置参数 转,展开是结果列表。如果 参数 是 下标为@或*的数组变量,替换操作 依次应用于数组的每个成员,展开为 结果列表。

参数扩展不限于这种替换,还有很多,见手册。

几个例子

为了可读性而放弃引用。

  1. 简单变量

    $ var='abcabc'
    $ echo ${var/a/X}   # Replace first 'a'
    Xbcabc
    $ echo ${var//a/X}  # Replace all 'a'
    XbcXbc
    $ echo ${var/a}     # Remove 'a'
    bcabc
    $ echo ${var//a}    # Remove all 'a'
    bcbc
    $ echo ${var/#b}    # Try to remove 'b' from start of string - no-op
    abcabc
    $ echo ${var/#a}    # Remove 'a' from start of string
    bcabc
    $ echo ${var/%b}    # Try to remove 'b' from end of string - no-op
    abcabc
    $ echo ${var/%c}    # Remove 'c' from end of string
    abcab
    
  2. 位置参数

    $ set -- abcabc defdef abcabc # Set $1, $2 and $3
    $ echo ${@/a/X}               # Replace first 'a' for each parameter
    Xbcabc defdef Xbcabc
    $ echo ${@//a/X}              # Replace all 'a' for each parameter
    XbcXbc defdef XbcXbc
    $ echo ${@/?/X}               # Replace first occurrence of any character
    Xbcabc Xefdef Xbcabc
    $ echo ${@//?/X}              # Replace all characters
    XXXXXX XXXXXX XXXXXX
    
  3. 数组

    $ arr=(abcabc defdef abcabc) # Create array
    $ echo ${arr[@]/a/X}         # Replace first 'a' in each element
    Xbcabc defdef Xbcabc
    $ echo ${arr[@]//a/X}        # Replace all 'a' in each element
    XbcXbc defdef XbcXbc
    $ echo ${arr[@]/?/X}         # Replace first character in each element
    Xbcabc Xefdef Xbcabc
    $ echo ${arr[@]//?/X}        # Replace all characters in all elements
    XXXXXX XXXXXX XXXXXX
    
  4. 组合

    这些也可以组合:

    $ arr=(patxxx xxpatxx xxxpat)  # Create array
    $ echo ${arr[@]/pat/X}         # Replace 'pat' in each element
    Xxxx xxXxx xxxX
    $ echo ${arr[@]/%pat/X}        # Replace 'pat' if it matches at the end
    patxxx xxpatxx xxxX
    $ echo ${arr[@]/#pat/X}        # Replace 'pat' if it matches at the beginning
    Xxxx xxpatxx xxxpat
    
  5. 扩展模式匹配

    与extended patterns一起,搜索和替换的参数扩展变得相当强大:

    $ printf -v var "%b" ' have_spaces\t'     # Has space and tab
    $ echo "$var" | cat -A                    # Show whitespace
     have_spaces^I$
    $ shopt -s extglob                        # Turn on extended pattern matching
    $ echo "${var//+([[:space:]])}" | cat -A  # Remove all whitespace
    have_spaces$
    

    这个例子有点做作,因为同样的问题可以更简单地解决——关键是它非常灵活。

【讨论】:

  • 谢谢,这适用于简单的事情,但有没有办法做类似sed 's/re/new/g' <<<"$VAR"
  • pattern 不被视为正则表达式,它是一个 glob。
  • @Samadi 那是${VAR//re/new},我已经添加了一些示例。
【解决方案2】:

你可以这样做:

sed 's/re/new' <<< "$var"

如果你想这样做并更新变量,你可以这样做:

var=$(sed 's/re/new' <<< "$var")

【讨论】:

  • 啊,谢谢,效果很好。我不知道&lt;&lt;&lt;
猜你喜欢
  • 2013-04-03
  • 2014-11-30
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 2017-03-04
  • 2020-03-16
  • 2018-11-17
  • 1970-01-01
相关资源
最近更新 更多