【问题标题】:Search for a pattern and replace something in the same line after = and ""搜索模式并在 = 和 "" 之后替换同一行中的内容
【发布时间】:2019-07-06 20:53:26
【问题描述】:

我正在尝试用其他一些 IP 替换 10.10.10.10,这些 IP 在脚本执行期间作为参数传递,因此它应该更新我的文件中包含以下代码的代码。 (例如...)

$cat environment.ts
.....
.........
const WEB_URL = 'http://10.10.10.10';
const API_URL = 'http://20.20.20.20:8080';
.....
............
......
END OF File

如果它只是 IP 地址,那么我可以直接使用 sed 命令如下,只需搜索 IP:10.10.10.10 并将其替换为一些 IP,例如 1.1.1.1

sed -i 's/10.10.10.10/1.1.1.1/g' environment.ts

但是,我不能中继 IP 地址,因为文件 "filename.ts" 可能有不同的 IP 经常更新。

所以我正在搜索模式 "WEB_URL" 并尝试在 '='"//" 之后替换新 IP。我试过sedawk 都没有成功

预期结果:

需要类似sedawk 的命令来替换上述文件"environment.ts" 中的旧IP,它应该用新IP 替换旧IP。 (如上所述,旧 IP 不是恒定的,它可能会有所不同,因此我使用的 sedawk 命令应使用 WEB_URLAPI_URL 之类的模式搜索并替换 @987654339 旁边的新 IP @或http//)

发件人:

.....
const WEB_URL = 'http://<OLD_IP1>';
const API_URL = 'http://<OLD_IP2>:8080';
.....

收件人:

const WEB_URL = 'http://<NEW_IP1>';
const API_URL = 'http://<NEW_IP2>:8080';

【问题讨论】:

  • 请发布一些示例数据以供使用 - 以及您希望输出的方式。

标签: linux bash shell powershell ubuntu


【解决方案1】:

可以编写sed 表单,它定位一个事件,然后使用备用分隔符来避免必须转义'/' 字符:

sed '/locate/s#find#replace#'

但由于您希望能够将 IP 作为变量传递,因此您需要将表达式双引号以进行变量扩展,并且我们将要使用 {x,y} 量词,因此我们将需要 -r启用扩展的正则表达式匹配的选项,结果如下:

sed -r "/locate/s#find#replace#"

在您的情况下,给定变量 ip 中提供的 IP,并且您希望找到 WEB_URLAPI_URL(后跟空格和 '=' 符号),然后仅将 IP 地址替换为包含在$ip 中,您可以使用:

sed -r "/(WEB|API)_URL\s=/s#[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}#$ip#"

你在哪里

  • 定位/(WEB|API)_URL\s=/
  • 查找 IP 为[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}
  • 替换$ip

输入文件示例

示例文件显示了保持不变的OTH_URLAPI_URL(后面没有空格和'='):

$ cat environment.ts
const OTH_URL = 'http://10.10.10.10';
const WEB_URL = 'http://10.10.10.10';
const API_URL = 'http://20.20.20.20:8080';
const API_URL (can either be 'http://10.10.10.10' or 'http://10.10.10.10:8080')

在上面的示例文件中运行 sed 表达式会导致:

$ ip=12.12.12.12
$ sed -r "/(WEB|API)_URL\s=/s#[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}#$ip#" \
environment.ts
const OTH_URL = 'http://10.10.10.10';
const WEB_URL = 'http://12.12.12.12';
const API_URL = 'http://12.12.12.12:8080';
const API_URL (can either be 'http://10.10.10.10' or 'http://10.10.10.10:8080')

OTH_URL 行或API_URL 后面没有空格且'=' 的行均保持不变。

如果需要,您需要单独调用以将 WEB_URLAPI_URL 更改为不同的 IP 地址。这可以通过使用单独的sed 表达式-e 来完成,例如:

$ ip1=12.12.12.12
$ ip2=14.14.14.14
$ sed -r -e "/WEB_URL\s=/s#[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}#$ip1#" \
         -e "/API_URL\s=/s#[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}#$ip2#" \
         environment.ts
const OTH_URL = 'http://10.10.10.10';
const WEB_URL = 'http://12.12.12.12';
const API_URL = 'http://14.14.14.14:8080';
const API_URL (can either be 'http://10.10.10.10' or 'http://10.10.10.10:8080')

检查一下,如果您有任何问题,请告诉我。

【讨论】:

    【解决方案2】:

    用 powershell 轻松搞定:

    Add-Type -AssemblyName System.Collections
    Add-Type -AssemblyName System.Text.RegularExpressions
    
    [System.Collections.Generic.List[string]]$content = @()
    
    $inputFile   = 'D:\content.txt'
    $outputFile  = 'D:\content1.txt'
    
    $regex       = '\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b'
    
    $newIP1      = '1.1.1.1'
    $newIP2      = '1.1.1.2'
    
    foreach($line in [System.IO.File]::ReadLines($inputFile)) {
    
        if( $line -like '*API_URL*' ) {
            [void]$content.Add( ($line -replace $regex, $newIP2) )
        elseif( $line -like '*WEB_URL*' ) {
            [void]$content.Add( ($line -replace $regex, $newIP1) )            }
        else {
            [void]$content.Add( $line )
        }
    }
    
    [System.IO.File]::WriteAllLines( $outputFile, $content ) | Out-Null
    

    【讨论】:

    • 不错;一些提示:不需要Add-Type 调用 - 默认情况下,感兴趣类型的程序集在 PowerShell 会话中可用。 [void] 强制转换和 Out-Null 调用是不必要的,因为您调用的方法不返回值。让PowerShell在数组中收集输出,而不是在$content中建立自己的列表,既方便又高效;只需在 foreach 循环中使用 隐式输出 并将 foreach 循环直接分配给变量 ($content = foreach ...)。
    • 此外,PowerShell 提供Get-Content 用于逐行读取文本文件,Set-Content 用于写入文本文件;只有在考虑性能时才需要直接使用 System.IO 类型。
    【解决方案3】:

    像这样使用sed

    #!/usr/bin/env sh
    # POSIX compliant shell script to replace WEB_URL and API_URL
    # into environment.ts
    
    NEW_WEB_URL='http://127.0.0.1/'
    NEW_API_URL='http://127.0.0.1:8080/'
    
    var_replace_value() {
      # Creates a sed command to replace
      # varname = "something" to varname = "somethingelse"
      # @Params
      # $1: varname
      # $2: newvalue
      [ $# -eq 2 ] || return 1
    
      _local_varname=''
      _local_newvalue=''
    
      # Escape parameters to fit a sed command
      _local_varname="$(echo "${1}" | \
        sed \
          --posix \
          --regexp-extended 's/([\\\/\(\)\{\}\[\$\^]|\])/\\\1/g')"
      _local_newvalue="$(echo "${2}" | \
        sed \
          --posix \
          --regexp-extended 's/([\\\/\(\)\{\}\[\$\^]|\])/\\\1/g')"
    
      env printf "s/(%s[[:space:]]*=[[:space:]]*['\"])[^'\"]+/\\\\1%s/g" \
        "${_local_varname}" \
        "${_local_newvalue}"
    }
    
    # Build the sed script to replace the URLs
    WEB_URL_REPLACE_CMD="$(var_replace_value 'WEB_URL' "${NEW_WEB_URL}")"
    API_URL_REPLACE_CMD="$(var_replace_value 'API_URL' "${NEW_API_URL}")"
    URL_REPLACE_SED_CMDS="${WEB_URL_REPLACE_CMD};${API_URL_REPLACE_CMD}"
    
    sed \
    --posix \
    --in-place='.bak' \
    --regexp-extended "${URL_REPLACE_SED_CMDS}" environment.ts
    

    【讨论】:

      【解决方案4】:

      我同意这比sed 多得多,但它确实有效。文件名、旧字符串、新字符串都可以做成.ps1脚本参数。

      $filetoworkon = 'environment.ts'
      $old = '10.10.10.10'
      $new = '7.7.7.7'
      
      Get-Content $filetoworkon |
          ForEach-Object {
              $_ -replace [regex]::Escape($old), $new
          }
      

      【讨论】:

      • 你需要做$_ -replace [regex]::Escape($old), $new,因为字符串中的点在正则表达式中具有特殊含义,即任何单个字符(而-replace使用正则表达式)..
      • @Theo - 谢谢你的建议。进行了更改。
      猜你喜欢
      • 2014-04-20
      • 2014-02-05
      • 2016-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-23
      • 2020-11-11
      • 2018-05-26
      相关资源
      最近更新 更多