替换“key: value”语句中的值,但仅限于文件中第一次出现该键时

替换“key: value”语句中的值,但仅限于文件中第一次出现该键时

我有一个 yml 文件

spring:
  datasource:
    url: url
    username:test
    password: testpwd
api:
  security:
    username:foo
    password: foopwd

我想在 Linux 计算机上使用命令行仅更新第一次出现的用户名和密码,如下所示:

spring:
  datasource:
    url: url
    username:toto
    password: totopsw
api:
  security:
    username:foo
    password: foopwd

当我尝试时:

sed -i -e 's!^\(\s*username:\)[^"]*!\1toto!' test.yml

他更改了所有用户名

答案1

另一种sed选择:

sed '1,/username/{/username/ s/:.*/:toto/};
     1,/password/{/password/ s/:.*/:totopsw/}' infile

1,/regex/从第一行开始到与给定匹配的第一行regex(这里是username字符串),更改“用户名”;对“密码”部分做同样的事情。

答案2

如果文件较长,这里有一个awk基于 - 的解决方案,可以按行处理它:

awk '/^[[:space:]]+username/ && !u_chng{sub(/:.+$/,": toto"); u_chng=1}
     /^[[:space:]]+password/ && !p_chng{sub(/:.+$/,": totospw"); p_chng=1} 1' input.yml 

username这将分别检查每一行是否以或开头password。如果是这样,并且关联的标志u_chngp_chng尚未设置,它将把 后面的值设置:为您想要的新值,并设置相应的标志,以便忽略这些关键字的任何进一步出现。

结果:

spring:
  datasource:
    url: url
    username: toto
    password: totospw
api:
  security:
    username:foo
    password: foopwd

请注意,如果您使用awk不理解字符类 ( [[:space:]]) 的实现,请更改

/^[[:space:]]+username/

/^[ \t]+username/

答案3

如果您的文件足够小,可以放入内存,您可以尝试将整个文件作为单个记录读取。这样,sed只会在第一次看到“行”(记录)上的模式时进行替换:

$ sed -Ez 's/(username:)[^\n]*/\1toto/; s/(password:)[^\n]*/\1totopsw/' file.yaml 
spring:
  datasource:
    url: url
    username:toto
    password:totopsw
api:
  security:
    username:foo
    password: foopwd

要在原始文件中进行更改,只需添加-i

sed -i -Ez 's/(username:)[^\n]*/\1toto/; s/(password:)[^\n]*/\1totopsw/' file.yaml 

答案4

如果bash脚本有效,您可以使用以下sed quit 命令:

#!/bin/bash

sed -E '
    # If we find an username
    /username/ {

        # make the sobstitution of the username
        s/^([[:space:]]*username:)/\1toto/g

        n # Take the next line with the password

        # Sobstitute the password
        s/^([[:space:]]*password:).*$/\1totopw/g

        q1 # Quit after the first match
    }
' test.yml > new_test.yml

# How many line we have taken
len_line=$(sed -n '$=' new_test.yml)

# write the other line
sed "1,${len_line}d" test.yml >> new_test.yml

# rename all the file
rm -f test.yml
mv new_test.yml test.yml

相关内容