동일한 표준 입력을 두 번 처리하고 출력을 추가합니다.

동일한 표준 입력을 두 번 처리하고 출력을 추가합니다.

다음과 같은 json 파일이 있습니다.

[
    {
        "key": "alt+down",
        "command": "-editor.action.moveLinesDownAction",
        "when": "editorTextFocus && !editorReadonly"
    },
    {
        "key": "alt+f12",
        "command": "editor.action.peekDefinition",
        "when": "editorHasDefinitionProvider && editorTextFocus && !inReferenceSearchEditor && !isInEmbeddedEditor"
    }
]
//  {
//      "key": "ctrl+shift+d",
//      "command": "workbench.action.toggleMaximizedPanel"
//  },
//  {
//      "key": "ctrl+shift+d",
//      "command": "-workbench.view.debug",
//      "when": "viewContainer.workbench.view.debug.enabled"
//  }

이 파일을 정렬하고 싶습니다.

jq//줄 시작 부분에 하나가 있으면 유효한 json이 아니기 때문에 오류가 발생합니다.

따라서 이 파일을 정렬하기 위해 내가 생각해낸 명령은 다음과 같습니다.

grep -v '^[ ]*//' keybindings.json | jq 'sort_by(.key)'

그러나 나는 주석이 달린 줄을 버리고 싶지 않습니다. 따라서 주석 처리된 줄을 얻기 위해 내가 생각해낸 명령은 다음과 같습니다.

grep '^[ ]*//' keybindings.json

이제 내 문제를 해결하기 위해 간단히 할 수 있는 일은 다음과 같습니다.

#!/bin/bash

SORTED_JSON=$(grep -v '^[ ]*//' keybindings.json | jq 'sort_by(.key)')
COMMENTED_JSON=$(grep '^[ ]*//' keybindings.json)

echo "$SORTED_JSON" >keybindings.json
echo "$COMMENTED_JSON" >>keybindings.json

하지만 문제가 있습니다!

이 작업은 하나의 명령으로 수행해야 합니다. 이는 vscode 설정을 통해 이 작업을 수행하기 때문입니다.

"filterText.commandList": [
    {
        "name": "Sort VSCode Keybindings",
        "description": "Sorts keybindings.json by keys. Select everything except the comment in fist line. Then run this command",
        "command": "jq 'sort_by(.key)'"
    }
]

선택한 텍스트를 표준 입력으로 가져와서 command처리하고, 처리된 텍스트를 출력합니다.

그래서 제가 이해한 바에 따르면 stdin을 두 번 읽어야 합니다(한 번 grep -v '^[ ]*//' | jq 'sort_by(.key)', 또 다시 grep '^[ ]*//'). 두 명령의 출력을 stdout에 추가합니다.

이 문제를 어떻게 해결할 수 있나요?

업데이트 1:

나는 그들 모두를 시도했다

cat keybindings.json| {grep -v '^[ ]*//' | jq 'sort_by(.key)' ; grep '^[ ]*//'}

그리고

cat keybindings.json| (grep -v '^[ ]*//' | jq 'sort_by(.key)' ; grep '^[ ]*//')

주석 줄은 표시되지 않습니다.

업데이트 2:

다음은 내가 기대했던 것과 가까운 것 같습니다. 그러나 여기서는 주석 처리된 줄이 주석 처리되지 않은 줄 앞에 옵니다.

$ cat keybindings.json| tee >(grep -v '^[ ]*//' | jq 'sort_by(.key)') >(grep '^[ ]*//') > /dev/null 2>&1
    //  {
    //      "key": "ctrl+shift+d",
    //      "command": "workbench.action.toggleMaximizedPanel"
    //  },
    //  {
    //      "key": "ctrl+shift+d",
    //      "command": "-workbench.view.debug",
    //      "when": "viewContainer.workbench.view.debug.enabled"
    //  }
[
  {
    "key": "alt+down",
    "command": "-editor.action.moveLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "alt+f12",
    "command": "editor.action.peekDefinition",
    "when": "editorHasDefinitionProvider && editorTextFocus && !inReferenceSearchEditor && !isInEmbeddedEditor"
  }
]

업데이트 3:

cat keybindings.json| (tee >(grep '^[ ]*//'); tee >(grep -v '^[ ]*//' | jq 'sort_by(.key)'))

또는,

cat keybindings.json| {tee >(grep '^[ ]*//'); tee >(grep -v '^[ ]*//' | jq 'sort_by(.key)')} 

또한 업데이트 3과 동일한 출력을 제공하는 것 같습니다(주석 처리되지 않은 행 앞에 주석 처리된 행).

답변1

주석 줄과 주석이 아닌 줄을 혼합하여 삽입하는 방법은 없습니다. 이를 별도의 블록으로 처리하고 별도로 처리해야 합니다.

주석 줄을 먼저 출력해도 괜찮다면 awk다음과 같이 사용할 수 있습니다.

awk '{ if ($0 ~ /^ *\/\//) { print } else { print | "jq \"sort_by(.key)\"" } }' keybindings.json

하지만 주석 줄이 끝에 나타나기를 원하므로 주석 줄을 저장하고 나중에 출력해야 합니다.

awk '
    # Define a convenience variable for the jq process
    BEGIN {
        jq = "jq \"sort_by(.key)\""
    }

    # Each line hits this. Either we save the comment or we feed it to jq
    {
        if ($0 ~ /^ *\/\//) { c[++i] = $0 }
        else { print | jq }
    }
    
    # Close the pipe to get its output and then print the saved comment lines
    END {
        close (jq);
        for (i in c) { print c[i] }
    }
' keybindings.json

이제 당신의 "명령 하나로 이 작업을 수행해야 합니다.". 자신만의 명령(프로그램, 스크립트)을 생성하는 것을 방해하는 것은 아무것도 없다는 것을 기억하십시오. 필요한 명령 세트를 파일에 넣고 해당 파일을 실행 가능하게 만든 다음 . .나는 사용 $PATH하고 있으며 내 및 .$HOME/binexport PATH="$PATH:$HOME/bin"~/.bash_profile~/.profile

답변2

주석을 문자열로 변환하고 배열을 정렬한 다음 주석 문자열을 다시 주석으로 변환합니다.

주석을 문자열로 변환하는 작업은 다음과 같습니다.

  1. //(선택적 들여쓰기 및 공백 포함)로 시작하는 줄을 감지합니다 .
  2. "이 줄에 있는 모든 항목을 \", 및
  3. 이 줄을 큰따옴표로 묶으세요.
sed '\:^ *//: { s/"/\\"/g; s/.*/"&"/; }'

그런 다음 배열을 정렬합니다.

jq 'if type == "array" then sort_by(.key) else . end'

마지막으로 주석 문자열을 다시 주석으로 변환합니다.

  1. "//(및 사이에 선택적 공백 포함)로 시작하고 다음으로 끝나는 줄을 감지합니다 ."//"
  2. 이 줄의 첫 번째 줄 ""마지막 줄 을 삭제하세요.
  3. 각각을 \"로 교체하세요 ".
sed '\:^"\( *//.*\)"$: { s//\1/; s/\\"/"/g; }'

표준 입력에서 완전히 읽는 파이프:

sed '\:^ *//: { s/"/\\"/g; s/.*/"&"/; }' |
jq 'if type == "array" then sort_by(.key) else . end' |
sed '\:^"\( *//.*\)"$: { s//\1/; s/\\"/"/g; }'

이는 데이터에 이스케이프된 큰따옴표가 아직 포함되어 있지 않다고 가정합니다.

답변3

나는 약간의 연구를 했기 때문에 내 질문에도 대답하고 싶었습니다. 한 줄 명령의 경우:

cat keybindings.json | (tee /tmp/program-code-binding.json | grep -v '^[ ]*//' | jq 'sort_by(.key)'; cat /tmp/program-code-binding.json | grep '^[ ]*//')

스크립트를 사용하려면 다음을 수행하십시오.

#!/bin/bash

THESTDIN=$(cat)

SORTED_JSON=$(echo "$THESTDIN" | grep -v '^[ ]*//' | jq 'sort_by(.key)')
COMMENTED_JSON=$(echo "$THESTDIN" | grep '^[ ]*//')

echo "$SORTED_JSON"
echo "$COMMENTED_JSON"

이 스크립트에는 극단적인 경우가 있습니다.THESTDIN=$(cat)파이프에 아무것도 없으면 무기한 매달립니다.. 이 문제를 해결하기 위해 스크립트는 실제로 다음과 같습니다.

#!/bin/bash

__=""
THESTDIN=""

read -N1 -t1 __  && {
    (( $? <= 128 ))  && {
        IFS= read -rd '' _stdin
        THESTDIN="$__$_stdin"
    }
}

SORTED_JSON=$(echo "$THESTDIN" | grep -v '^[ ]*//' | jq 'sort_by(.key)')
COMMENTED_JSON=$(echo "$THESTDIN" | grep '^[ ]*//')

echo "$SORTED_JSON"
echo "$COMMENTED_JSON"

관련 정보