Bash: 여러 줄을 한 줄 명령으로 구문 분석

Bash: 여러 줄을 한 줄 명령으로 구문 분석

다른 Bash 스크립트에 특정 명령줄이 포함되어 있는지 확인하는 Bash 스크립트를 작성해야 합니다. Bash를 사용하면 명령줄을 여러 줄로 분할할 수 있으므로 내 스크립트는 실제 패턴 일치를 수행하기 전에 해당 줄을 병합할 수 있어야 했습니다.

Bash 스크립트의 모든 여러 줄 명령을 한 줄 명령으로 구문 분석하는 방법은 무엇입니까?

특정 스크립트에 포함되어 있는지 확인하고 싶습니다.엘에스명령 - 다음을 포함하는 경우엘에스명령에서 어떤 매개변수가 전달되는지 알고 싶습니다.엘에스주문하다. 이 질문에 대답하기 위해 사용할 수 있습니다sed. 하지만 먼저 모든 여러 줄 명령을 병합해야 합니다.

입력하다:

# My comment \
ls \
-a \
-l

산출:

# My comment \
ls -a -l

잘못된 출력의 예:

# My comment ls -a -l

답변1

나는 쉘 쇼크 직전에StackOverflow에 대한 질문에 답변했습니다.Bash 스크립트에서 주석 제거에 대해. 내 대답은 스크립트 파일의 내용을 래핑한 tmp_() { ... }다음 declare -f tmp_이를 사용하여 함수를 예쁘게 인쇄하는 간단한 방법을 사용합니다. 예쁜 인쇄 출력에는 주석이 없으며 백슬래시 줄 바꿈으로 계속되는 줄은 단일 줄로 구문 분석됩니다. (내부 역따옴표 명령 대체는 제외)

다른 포맷도 완료되었습니다. 예를 들어 복합 명령은 여러 줄로 구분됩니다. 그리고 라인 연속의 일부 형태는 다시 형식화되지 않습니다. 예를 들어 파이프 기호로 끝나는 라인은 변경되지 않습니다. 하지만 이 질문의 사용 사례를 충족해야 합니다. (아래 샘플 출력을 참조하세요.)

물론 함수 정의를 평가해야 합니다. 이는 아름답게 인쇄된 스크립트에 주입 공격이 포함될 수 있음을 의미합니다. 내가 제안하는 코드에서 함수 정의는 함수를 내보내고 하위 프로세스와 공유할 수 있는 bash 기능을 통해 평가됩니다. 이 작은 해킹을 작성할 때 나는 메커니즘이 를 호출하는 것보다 더 안전하다고 믿었 eval지만 알고 보니 내 생각이 틀렸습니다.

함수 정의를 가져오기 위해 bash가 사용하는 코드는 shellshock 이후 많이 개선되었습니다. 이는 적어도 일부 주입 공격을 방지하지만 분명히 프로세스가 완전히 안전하다는 보장은 없습니다.

분석 중인 스크립트를 실행하는 경우 이 프로세스를 사용하여 취약성을 증가시키지 않을 수 있습니다. 공격자는 잠재적으로 우회 가능한 보안 검사를 통해 코드를 가져와서 숨길 필요 없이 스크립트에 직접 위험한 코드를 삽입할 수 있습니다. 공격.

그럼에도 불구하고 이 작은 프로그램이든 임의의 스크립트를 실행해야 하는 계획이든 보안 문제를 신중하게 고려해야 합니다.

다음은 shellshock 패치가 적용된 bash에서 작동하는(이전 bash 버전에서는 작동하지 않는) 예쁜 프린터 버전입니다.

env "BASH_FUNC_tmp_%%=() {
$(<script_name)
}" bash -c 'declare -f tmp_' | tail -n+2

script_name두 번째 줄을 스크립트가 포함된 파일 이름으로 바꾸세요. 명령을 조정하면 tail래퍼 함수 이름이 제거되지만 스크립트 본문 주위의 중괄호는 제거되지 않습니다.

원래 버전은 bash의 쉘쇼크 이전 버전용이며 참조된 SO 답변에서 찾을 수 있습니다.


견본.

제공된 입력에 대해 테스트스티븐 차제라스:

{ 
    echo \\;
    echo a#b;
    echo 'foo\
bar';
    cat  <<EOF
thisis joined
this 'aswell'
$(ls -l)
EOF

    cat  <<'EOF'
this is\
not joined
EOF

    echo "$(ls -l)";
    echo `ls \\
-l`
}

이는 Stéphane이 제안한 출력과 다릅니다.

  • 줄은 들여쓰기되어 있으며 많은 줄이 세미콜론으로 끝납니다. 많은 줄에서 공백이 추가 및/또는 제거되었습니다.
  • cat << E\OFcat <<'EOF'동일한 의미를 갖는 로 변경되었습니다 .
  • 끝에 백틱 명령을 대체하는 중첩된 연속 행은 수정되지 않았습니다. (명령 대체에서 연속된 줄은 $(...)제거됩니다.)

답변2

이제 이것은 더 많은 경우에 작동하며 예상대로 작동하는지 확인하십시오.

sed ':loop /^[^#].*[^\\]\\$/N; s/\\\n//; t loop' input

기본적으로 각 줄을 인쇄합니다. 줄 끝에 백슬래시($)가 있고(특수 문자이기 때문에 이스케이프됨) 줄 시작 부분에 해시 표시가 없으면 수정된 다음 줄과 비교합니다. line (N) 검색을 연결하고 백슬래시(다시 이스케이프됨)와 개행 문자를 바꿉니다.아무것도 없다. 검색 및 바꾸기가 일부 작업을 수행하는 경우 루프 탭으로 돌아가서 검색을 다시 실행하세요.

입력하다:

# My comment \
ls \
-al

# leading comment
echo some \
long \
text
# trailing comment

ls -al

산출:

# My comment \
ls -al

# leading comment
echo some long text
# trailing comment

ls -al

답변3

이는 실제로 답변이 아니며 일반적인 경우에 작동하는 솔루션을 위해 고려해야 할 사항에 대한 참고 사항일 뿐입니다.

#! /bin/sh -
echo \\
echo a#\
b
echo 'foo\
bar'
cat << EOF
this\
is joined
this 'as\
well'
$(ls \
-l)
EOF
cat << E\OF
this is\
not joined
EOF
echo "$(ls \
-l)"
echo `ls \\
-l`

질문의 의도에 대한 나의 이해는 다음과 같이 변환되어야 한다는 것입니다.

#! /bin/sh -
echo \\
echo a#b
echo 'foo\
bar'
cat << EOF
thisis joined
this 'aswell'
$(ls -l)
EOF
cat << E\OF
this is\
not joined
EOF
echo "$(ls -l)"
echo `ls -l`

답변4

줄 바꿈을 공백으로 바꾸려면 다음을 수행하십시오.

tr '\n' ' '

이로 인해 코드에 일부 백슬래시가 남을 수 있으므로 백슬래시 앞의 개행 문자를 공백으로 바꿔야 할 수 있습니다.

 perl -pe 's/\\\n/ /'

이것은 여전히 ​​​​잘못될 수 있지만 (여기 문서, 설명 등이 있습니다) 100% 정확하려면 완전한 쉘 파서를 작성해야 합니다.

관련 정보