고쳐 쓰다

고쳐 쓰다

cidr 목록이 포함된 파일이 있습니다. Bash 스크립트를 사용하여 다음 형식으로 큰 json을 만드는 방법 단일 CIDR 보유

[{"source":"1.1.1.0/32","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":65535,"min":1},"sourcePortRange":{"min":521,"max":65535}}}]

CIDR이 여러 개 있음

[{"source":"1.1.1.0/24","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":55555,"min":10001},"sourcePortRange":{"min":521,"max":65535}}},{"source":"2.2.2.0/24","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":55555,"min":10001},"sourcePortRange":{"min":521,"max":65535}}},{"source":"3.3.3.0/24","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":55555,"min":10001},"sourcePortRange":{"min":521,"max":65535}}}]

200개 항목으로 하고 싶습니다. json이 어떻게 작동하는지 전혀 모릅니다. 누구든지 나를 도와줄 수 있나요? 해당 json을 bash 스크립트의 변수로 사용하고 싶습니다.

입력 CIDR 파일은 다음과 같습니다.

1.1.1.0/22
2.2.2.0/24
5.5.5.0/21
6.6.0.0/16

bash 스크립트에서 주어진 솔루션을 시도했지만 \r모든 CIDR 에 가까워졌습니다.

스크립트:

#!/bin/bash

lel=$(while read cidr ; do 
   jq -n --arg CIDR "$cidr" '[{"source":$CIDR,"protocol":"17","isStateless":true,"udpOptions": {"destinationPortRange":{"max": 65535,"min": 1},"sourcePortRange": {"min":521,"max": 65535}  }}]' 
done < lol)
echo $lel

하하 파일:

1.22.0.0/15
1.38.0.0/15
1.186.0.0/15
14.96.0.0/14

산출

[ { "source": "1.22.0.0/15\r", "protocol": "17", "isStateless": true, "udpOptions": { "destinationPortRange": { "max": 65535, "min": 1 }, "sourcePortRange": { "min": 521, "max": 65535 } } } ] [ { "source": "1.38.0.0/15\r", "protocol": "17", "isStateless": true, "udpOptions": { "destinationPortRange": { "max": 65535, "min": 1 }, "sourcePortRange": { "min": 521, "max": 65535 } } } ] [ { "source": "1.186.0.0/15\r", "protocol": "17", "isStateless": true, "udpOptions": { "destinationPortRange": { "max": 65535, "min": 1 }, "sourcePortRange": { "min": 521, "max": 65535 } } } ] [ { "source": "14.96.0.0/14\r", "protocol": "17", "isStateless": true, "udpOptions": { "destinationPortRange": { "max": 65535, "min": 1 }, "sourcePortRange": { "min": 521, "max": 65535 } } } ]

답변1

데이터와 코드에는 두 가지 주요 문제가 있습니다.

  1. DOS 또는 Windows 텍스트 파일 형식의 입력 파일이 있습니다.
  2. 코드는 여러 요소가 포함된 단일 배열 대신 여러 단일 요소 배열을 만듭니다.

입력 파일이 lolDOS/Windows 형식의 텍스트 파일인 것 같습니다. 이는 Unix 텍스트 파일을 입력으로 요구하는 유틸리티가 파일을 읽을 때 \r각 줄 끝에 추가 캐리지 리턴( )이 있음을 의미합니다.

파일을 Unix 텍스트 파일 형식으로 변환해야 합니다. 이는 dos2unix다음과 같은 방법 으로 수행할 수 있습니다 .

코드의 경우 쉘 루프를 피하고 jq한 번에 전체 파일을 읽을 수 있습니다. 이를 통해 코드에서 수행하는 것과 같은 각각 하나의 개체가 포함된 배열 집합이 아닌 단일 결과 배열을 만들 수 있습니다.

다음은 결과에서 최상위 배열 요소 간의 유일한 차이점이 값이라고 가정합니다 source(질문에는 소스 및 대상 포트의 최대값과 최소값을 선택하는 방법에 대한 설명이 없습니다).

jq -n -R '
        [inputs] |
        map( {
                source: .,
                protocol: "17",
                isStateless: true,
                udpOptions: {
                        sourcePortRange: { min: 521, max: 65535 },
                        destinationPortRange: { min: 1, max: 65535 }
                }
        } )' cidr.txt

또는 귀하의 질문과 동일한 간결한 한 줄 형식으로 작성하십시오.

jq -n -R '[inputs]|map({source:.,protocol:"17",isStateless:true,udpOptions:{sourcePortRange:{min:521,max:65535},destinationPortRange:{min:1,max:65535}}})' cidr.txt

inputs, 를 사용하여 jq나머지 입력을 읽습니다. 와 함께 의 각 줄을 단일 문자열로 -R읽습니다 . cidr.txt이것을 배열에 넣으면 [inputs]문자열 배열이 생성됩니다. 이 호출은 이 배열에서 각 문자열을 가져와 더 큰 정적 개체의 값 map()으로 변환합니다 .source

"컴팩트" 출력을 얻기 위해 -c호출에 추가되었습니다 .jq


입력 데이터를 DOS에서 Unix 텍스트 형식으로 변환하는 것을 원하지 않거나 변환할 수 없는 경우 표현식에서 캐리지 리턴을 제거할 수 있습니다 jq.

이렇게 하려면 외부 대괄호를 포함하여 .이후를 source:로 바꾸십시오. (.|rtrimstr("\r"))이렇게 하면 파일에서 읽은 모든 문자열의 끝에서 캐리지 리턴이 제거됩니다.

답변2

답변

그러면 필요한 정확한 구문이 제공됩니다.

예에서 CIDR 값이 포함된 파일의 이름은 cidr.txtIP 주소와 서브넷만 포함된 것으로 나타납니다. 즉, 다른 매개변수는 변경되지 않은 상태로 유지됩니다. 이러한 추가 매개변수를 변경해야 하는 경우(예: 제공한 포트 범위가 실제로 모든 cidr에 대해 동일하지 않은 경우 답변을 업데이트하고 완전한 템플릿을 제공하겠습니다)

또한 bash를 통해 JSON을 처리하기 위한 범용 애플리케이션인 'jq'가 필요합니다. 요즘에는 이미 설치되어 있을 수도 있지만, 그렇지 않은 경우 sudo apt install jq평소대로 설치하면 됩니다.

while read cidr ; do 
   jq -n --arg CIDR "$cidr" '{"source":$CIDR,"protocol":"17","isStateless":true,"udpOptions": {"destinationPortRange":{"max": 65535,"min": 1},"sourcePortRange": {"min":521,"max": 65535}  }}'  
done < cidr.txt | jq --slurp

제공한 4줄 파일 예제를 사용하면 위 출력은 터미널에 다음을 제공합니다.

[
  {
    "source": "1.1.1.0/22",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 65535,
        "min": 1
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  },
  {
    "source": "2.2.2.0/24",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 65535,
        "min": 1
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  },
  {
    "source": "5.5.5.0/21",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 65535,
        "min": 1
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  },
  {
    "source": "6.6.0.0/16",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 65535,
        "min": 1
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  }
]


고쳐 쓰다

위 출력을 수정하려면 CIDR 파일의 줄 종료를 "수정"해야 합니다. 이를 수행하는 방법에는 두 가지가 있습니다.

답변 1:

스크립트를 다음과 같이 변경할 수 있습니다.

#!/bin/bash

# There are four changes made to the script:
# 1. The addition of `tr` in order to eliminate '\r'.
# 2. Removal of '[' and ']' inside the `jq` command.
# 3. Addition of `jq --slurp` to enforce your specified JSON format. 
# 4. Addition of double-quotes around `$lel` to prevent splitting.

 
lel=$(while read cidr ; do 
       cidr=$(echo "$cidr" | tr -d '\r' );     
       jq -n --arg CIDR "$cidr" '{"source":$CIDR,"protocol":"17","isStateless":true,"udpOptions": {"destinationPortRange":{"max": 65535,"min": 1},"sourcePortRange": {"min":521,
"max": 65535}  }}' 
  done < lol | jq --slurp )
echo "$lel"

대체 답변

CIDR 목록이 포함된 파일을 "복구"할 수 있습니다.

cp lol lol_old
cat lol_old | tr -d '\r' > lol

위에 포함된 스크립트의 주석 #2-4에 설명된 수정 사항이 있더라도 이전 버전의 스크립트를 사용할 수 있습니다.

설명하다

\r출력에서 발견된 이유는 실제로 CIDR을 포함하는 특정 파일의 형식에서 발견되며 이는 Windows(Unix는 아님) 줄 종료 표준을 따릅니다.

\r출력에 표시되는 기호는 실제로 소스 파일에도 존재하며 \n각 줄을 종료하는 데 사용됩니다. 그리고 보이지 않는 문자 \r입니다 \n. 이 조합을 \r\nCRLF(캐리지 리턴 + 라인 피드)라고 합니다. 이는 타자기 시대의 잔재이지만 어떤 이유로 Windows 시스템에서 여전히 사용됩니다. 반면 유닉스는 \n이스케이프 형식으로 표현되는 줄을 끝내기 위해 LF만 사용합니다.

이 특이한 동작을 확인하려면 다음 명령을 시도해 보세요.

head -n 1 lol | xxd -ps 
312e312e312e302f32320d0a

위 출력에서(16진수 형식으로 변환된 파일의 첫 번째 줄)은 입니다 0d0a. 이 16진수 조합은 CR+LF를 나타냅니다. 반면에 Bash 터미널 내에서 직접 다음 명령을 실행하는 경우:

echo "abcd"  | xxd -ps
616263640a

출력은 줄 종결자가 0aLF의 16진수 표현인 simple 을 사용하는 Unix 표준을 따른다는 것을 알 수 있습니다.

노트:이 줄 종료 문제는 매우 일반적이고 널리 퍼져 있으며 Windows에서 생성된 파일을 Unix 내에서 작업할 때 항상 주의가 필요합니다.



에 관한 정보jq

위의 예(loop while read)는 출력을 터미널로 보내지만 표준 구문을 사용하여 파일에 저장해야 하는 경우 물론 리디렉션을 사용할 수 있습니다.

while read cidr; do [...] ; done < cidr.txt > outcidr.json

파일에는 깔끔하게 인쇄된 JSON 출력이 포함되지만 출력을 한 줄로 제한해야 하거나 원하는 경우 다음을 수행할 수 있습니다.

cat outcidr.json | tr -d '\n' | tr -s ' '

게다가, 나중에 해독할 수 없을 것 같은 한 줄의 복잡한 JSON 출력으로 끝나는 경우 jq이를 사용하여 형식을 다시 지정하고 예쁘게 인쇄할 수 있습니다.

echo '[{"source":"1.1.1.0/24","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":55555,"min":10001},"sourcePortRange":{"min":521,"max":65535}}},{"source":"2.2.2.0/24","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":55555,"min":10001},"sourcePortRange":{"min":521,"max":65535}}},{"source":"3.3.3.0/24","protocol":"17","isStateless":true,"udpOptions":{"destinationPortRange":{"max":55555,"min":10001},"sourcePortRange":{"min":521,"max":65535}}}]' > bad_output.json

cat bad_output.json | tr -d '\r' | jq '' 

[
  {
    "source": "1.1.1.0/24",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 55555,
        "min": 10001
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  },
  {
    "source": "2.2.2.0/24",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 55555,
        "min": 10001
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  },
  {
    "source": "3.3.3.0/24",
    "protocol": "17",
    "isStateless": true,
    "udpOptions": {
      "destinationPortRange": {
        "max": 55555,
        "min": 10001
      },
      "sourcePortRange": {
        "min": 521,
        "max": 65535
      }
    }
  }
]
# Getting first-order keys for each of the 3 objects 
 
jq '.[] | keys' bad_output.json 

[
  "isStateless",
  "protocol",
  "source",
  "udpOptions"
]
[
  "isStateless",
  "protocol",
  "source",
  "udpOptions"
]
[
  "isStateless",
  "protocol",
  "source",
  "udpOptions"
]

# Getting values corresponding to the selected key"  
jq '.[] | .source ' outcidr.txt 
"1.1.1.0/22"
"2.2.2.0/24"
"5.5.5.0/21"
"6.6.0.0/16"

관련 정보