sed 매개변수가 여러 줄의 따옴표로 묶인 문자열로 대체되었습니다.

sed 매개변수가 여러 줄의 따옴표로 묶인 문자열로 대체되었습니다.

표적

텍스트를 "scripts: {"다음 문자열로 바꾸십시오.

"scripts": {
    "watch": "tsc -w",

파일 에서 json.

노력하다

소스 문자열과 대상 문자열에 대해 두 개의 변수를 만들었습니다.

첫 시도

SRC='"scripts": {'
DST='"scripts": {
    "watch": "tsc -w",'

그리고 다음 명령을 실행하세요:

sed "s/$SRC/$DST/" foo.json

이것은 실패했습니다.

두 번째 시도

이번에는 소스 및 대상 문자열에 대해 큰따옴표를 이스케이프 처리했습니다.

SRC="\"scripts\": {"
DST="\"scripts\": {
    \"watch\": \"tsc -w\",
    \"dev\": \"nodemon dist/index.js\","

위와 동일한 명령을 실행했지만 실패했습니다.

세 번째와 네 번째 시도

다음을 사용하여 위에 정의된 변수를 시도했습니다.

sed 's/'"$SRC"'/'"$DST"'/' foo.json

이것은 실패했습니다.

이러한 모든 시도에서 오류가 발생했습니다.

unterminated 's' command

무엇이 잘못되었나요?

답변1

JSON 문서가 다음과 같다고 가정해 보겠습니다.

{
  "scripts": {
    "other-key": "some value"
  }
}

...이 객체에 다른 키-값 쌍을 삽입하려고 합니다 .scripts. 그런 다음 다음을 사용할 수 있습니다 jq.

$ jq '.scripts.watch |= "tsc -w"' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w"
  }
}

또는,

$ jq '.scripts += { watch: "tsc -w" }' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w"
  }
}

둘 다 할 것이다바꾸다이미 존재하는 .scripts.watch항목입니다.

키-값 쌍의 순서는 .scripts중요하지 않습니다(배열이 아니기 때문에).

출력을 저장하려면 새 파일로 리디렉션하세요.

동일한 객체에 여러 키-값 쌍을 추가합니다.

$ jq '.scripts += { watch: "tsc -w", dev: "nodemon dist/index.js" }' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js"
  }
}

jo객체에 추가해야 하는 JSON을 생성하기 위해 결합되었습니다 .scripts.

$ jq --argjson new "$( jo watch='tsc -w' dev='nodemon dist/index.js' )" '.scripts += $new' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js"
  }
}

sed줄 중심 텍스트를 구문 분석하는 데 적합합니다. JSON에는 줄 바꿈으로 구분된 레코드가 포함되어 있지 않으며 sedJSON의 인용 및 문자 인코딩 규칙을 이해하지 못합니다. 이러한 구조화된 데이터 세트(또는 XML, YAML 또는 경우에 따라 CSV)를 올바르게 구문 분석하고 수정하려면 적절한 구문 분석기를 사용해야 합니다.

이 예제를 사용하면 추가 보너스로 jq다음과 같은 코드를 얻을 수 있습니다.용이하게필요에 맞게 수정하고 입력 데이터 구조에 대한 변경을 지원하도록 쉽게 수정할 수도 있습니다.

답변2

Kosalonanda는 절대적으로 옳습니다전용 파서가 작업에 적합한 도구라고 말합니다. 그러나 이것은 sed(적어도 GNU를 이해하는 경우 ) 쉽게 수행할 수 있습니다 sed. \n두 줄 패턴 전체를 바꾸려고 하면 상황이 더 복잡해집니다. 대신, 그냥성냥문자열을 대상으로 하고 그 뒤에 대체 내용을 삽입합니다.

"scripts": {

그런 다음:

$ sed '/"scripts": {/s/$/\n    "watch": "tsc -w",/' file
"scripts": {
    "watch": "tsc -w",

이는 "이 줄이 문자열과 일치하는 경우 "scripts": {줄 끝을 줄 바꿈 문자( \n)와 줄 바꿈 문자( )로 바꿉니다 "watch": "tsc -w",. 또는 ased 명령을 사용하여 텍스트를 추가할 수 있습니다.

$ sed '/"scripts": {/a\    "watch": "tsc -w",' file 
"scripts": {
    "watch": "tsc -w",

답변3

여기서는 Sed 명령을 생성하고 여기에 개행 문자를 추가합니다.

sed "s/$SRC/$DST/" foo.json

줄 바꿈으로 명령이 종료되므로 이는 유효하지 않습니다. \n문자 그대로의 개행 문자 대신에 작성해야 합니다 . 일부 쉘(Bash, zsh 등..., 그러나 일반 POSIX 쉘은 아님)에서는 매개변수 대체를 사용하여 이를 수행할 수 있습니다.

DST=${DST//$'\n'/\\n}
#        //             replace every
#          $'\n'        newline
#               /       with
#                \\n    \ and n 

다른 대체 문자열의 경우 따옴표가 필요할 수도 있습니다 /.

DST=${DST//\//\\/}

또한 \(이것을 먼저 수행합니다)은 &대체 텍스트에서 특별한 의미를 가지므로 대체가 필요합니다.

답변4

sed모든 텍스트가 고려 되므로 문자열을 코드 regex에 삽입하기 전에 문자열을 sed이스케이프 해야 합니다. 또한 입력한 문자열이 명령의 왼쪽에 있는지 오른쪽에 있는지 주의 깊게 살펴봐야 합니다 s///. 양쪽의 BRE 문자 목록이 다르기 때문입니다.

s='[[:blank:]]'
srch_str='"scripts": {'
repl_str='"watch": "tsc -w",'

esc_srch_str=$(
  printf '%s\n' "$srch_str" |
  sed -e 's:[][\/.^$*]:\\&:g'
)

esc_repl_str=$(
  printf '%s\n' "$repl_str" |
  sed -e 's:[\/&]:\\&:g'
)

sed -e "
  /^$s*$esc_srch_str\$/G
  s/^\($s*\).*\n/&\1  $esc_repl_str/
" file

산출:

{
  "scripts": {
    "watch": "tsc -w",
    "other-key": "some value"
  }
}

관련 정보