sed 명령의 올바른 배포

sed 명령의 올바른 배포

sed 명령의 결과를 bash의 변수에 할당하려고 하지만 모든 것을 올바르게 이스케이프할 수는 없습니다(아마도 bash 지식이 부족하기 때문일 것입니다). 다음을 시도했습니다.

hash_in_podfile=$( sed -rn 's/^ *pod [\'\"]XXX["\'],.*:commit *=> *["\']([^\'"]*)["\'].*$/\1/p' ${PODS_PODFILE_DIR_PATH}/Podfile )

그런데 점점 더 많아지네요

bash_playground.sh: line 9: 일치하는 ""를 찾는 동안 예기치 않은 EOF가 발생했습니다.

업데이트된 스크립트

다음은 내가 사용하고 있는 스크립트이며 답변의 코드로 업데이트되었습니다. 경로와 설명만 변경되었습니다.

#!\bin\sh
PODS_PODFILE_DIR_PATH='/Users/path/to/file'

# just a comment
hash_in_podfile=$(sed -rnf - <<\! -- "${PODS_PODFILE_DIR_PATH}/Podfile"
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
!
)
echo $hash_in_podfile

실행 및sh script_name.sh

sh --version생산하다:

GNU bash, 버전 3.2.57(1)-릴리스(x86_64-apple-darwin20) Copyright (C) 2007 Free Software Foundation, Inc.

실행할 때 다음을 얻습니다.

script_name.sh: line 6: unexpected EOF while looking for matching `"'
script_name.sh: line 10: syntax error: unexpected end of file

답변1

스크립트에는 두 가지 문제가 있습니다.

  1. macOS의 셸은 sh매우 오래된 버전이며 bash여기에 명령 대체에 설명된 대로 불균형 따옴표를 사용하지 못하게 하는 버그가 있습니다.

    $ a=$( cat <<'END'
    > "
    > END
    > )
    > sh: unexpected EOF while looking for matching `"'
    

    (마지막에 눌러야해요 Ctrl+D. ))

    Homebrew 패키지 관리자(또는 이에 상응하는 것)에서 최신 셸을 설치하거나 bashmacOS에서 셸을 사용하여 이 문제를 해결할 수 있습니다.zsh

  2. macOS sed에는 그러한 옵션이 없습니다 -r. sedmacOS에서 확장 정규식을 사용 하려면 -E(이제 GNU에서도 지원됨 sed)을 사용하세요. 그러나 표현식은 확장 정규식 기능을 사용하지 않으므로 해당 옵션을 제거하기만 하면 작동합니다. 또한 macOS는 "표준 입력에서 읽기"를 의미하는 옵션 인수 sed로 사용할 수 없습니다 . 대신 사용하십시오 .--f/dev/stdin

제안:

#!/bin/zsh

PODS_PODFILE_DIR_PATH='/Users/path/to/file'

# just a comment

hash_in_podfile=$(sed -n -f /dev/stdin -- $PODS_PODFILE_DIR_PATH/Podfile <<'END'
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
END
)

echo $hash_in_podfile

값만 출력하려면 중간 변수를 사용하지 마세요.

#!/bin/zsh

PODS_PODFILE_DIR_PATH='/Users/path/to/file'

# just a comment

sed -n -f /dev/stdin -- $PODS_PODFILE_DIR_PATH/Podfile <<'END'
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
END

답변2

heredoc방법이 시스템에서 작동하지 않으면 쉘 변수를 통해 sed 명령에 대한 대안을 제공하도록 선택할 수 있습니다.

hash_in_podfile=$(q=\"\'; sed -ne "s/^ *pod [$q]XXX[$q],.*:commit *=> *[$q]([^$q]*)[$q].*\$/\\1/p" -- "${PODS_PODFILE_DIR_PATH}/Podfile")

이를 수행하는 방법은 여러 가지가 있지만 가장 간단한 방법은 인용된 heredoc을 통해 stdin에 sed 명령을 제공하여 쉘에 적합한 sed 문자를 이스케이프 처리할 필요가 없도록 하는 것입니다.

hash_in_podfile=$(sed -rnf - <<\! -- "${PODS_PODFILE_DIR_PATH}/Podfile"
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
!
)

답변3

hash_in_podfile="$( sed -rn 's/^ *pod ['\''"]XXX["'\''],.*:commit *=> *["'\'']([^'\''"]*)["'\''].*$/\1/p' "${PODS_PODFILE_DIR_PATH}/Podfile" )"

echo 'before'\''after'기본 "트릭"은 작은 따옴표 안의 작은 따옴표를 " 이스케이프 "하는 방법입니다 before'after. Bash 확장의 작동 방식을 고려하면 예상대로 단일 토큰이 형성됩니다. 동등한 옵션은 이지만 echo 'before'"'"'after'이전 구문은 약간 더 짧습니다.

확장 명령이 올바른지 확인하려면 인쇄해 보세요.

echo sed -rn 's/^ *pod ['\''"]XXX["'\''],.*:commit *=> *["'\'']([^'\''"]*)["'\''].*$/\1/p' "${PODS_PODFILE_DIR_PATH}/Podfile"

그런데 심하게 오래된 버전보다는 최신 소프트웨어(예: Bash의 버전은 5.1.8)를 사용하는 것이 더 좋습니다. 어떤 경우에는 버전 차이가 크면 문제를 재현하기 어렵고 권장 사항을 따르기가 어려울 수 있습니다.

관련 정보