함수나 스크립트에서 *실제*(해석되지 않은) 쉘 인수를 얻는 방법이 있습니까?

함수나 스크립트에서 *실제*(해석되지 않은) 쉘 인수를 얻는 방법이 있습니까?

posix저는 Windows의 Git bash 쉘에서 DOS 스타일 경로를 일반 Unix 스타일 경로로 변환하는 함수를 사용하고 있습니다. DOS 스타일 경로는 백슬래시를 구분 기호로 사용하므로 쉘이 백슬래시를 사용하여 다음 문자를 리터럴로 표시하지 못하도록 경로 매개변수를 인용해야 합니다. 얻을 수 있는 방법이 있나요?설명할 수 없는내 함수 내부의 매개변수이므로 인용할 필요가 없나요?

도움이 된다면 내 기능은 다음과 같습니다.

function posix() {
  echo $1 | sed -e 's|\\|/|g' | sed -re 's|^(.)\:|/\L\1|'
}

(그런데, 나는 무엇이든 환영합니다논평인용/셸 해석 문제 해결과 관련이 없는 다른 방법으로 기능을 개선하기 위한 팁도 있습니다. )

답변1

해석되지 않은 쉘 매개변수에는 등이 포함됩니다 $1. $2대부분의 경우 매개변수 값의 추가 확장을 방지하려면 확장을 큰따옴표로 묶어야 합니다. "$@"모든 매개변수 목록을 제공합니다.

예를 들어, 쉘 스크립트의 인수를 함수에 전달하려면 다음과 같이 호출하십시오.

first_argument_as_filename_in_unix_syntax=$(posix "$1")

큰따옴표가 필요합니다. 을 쓰면 posix $1첫 번째 인수의 값이 아니라 첫 번째 인수 값에 대해 토큰화 및 와일드카드를 수행한 결과를 전달하게 됩니다. 또한 스크립트를 호출할 때 올바른 참조를 사용해야 합니다. 예를 들어, bash에서 다음과 같이 작성한다면:

myscript c:\path with spaces\somefile

그러면 해석되지 않은 실제 매개변수는 , 및 가 myscript됩니다 . 그러니 하지 마세요.c:pathwithspacessomefile

귀하의 posix기능이 잘못되었습니다. 다시 한 번 큰따옴표가 누락되었기 때문입니다 $1.변수와 명령 대체는 항상 큰따옴표( "$foo", ) 로 묶습니다 "$(foo)".실제로 따옴표가 필요하지 않은 예외를 기억하는 것보다 이 규칙을 기억하는 것이 더 쉽습니다.

echo경우에 따라 자체 처리를 수행하고 외부 프로세스 호출이 느립니다(특히 Windows에서). bash에서 전체 프로세스를 수행할 수 있습니다.

posix () {
  path="${1//\\//}"
  case "$path" in
    ?:*) drive="${p:0:1}"; drive="${drive,}"; p="/$drive/${p:2}";;
  esac
  printf %s "$p"
}

jw013에서 언급한 zsh 기능당신이 생각하는 대로 되지 않습니다. noglob명령 앞에 넣을 수 있으며 zsh는 인수에 와일드카드 지정(예: 파일 이름 생성, 즉 와일드카드 확장)을 수행하지 않습니다. 예를 들어 zsh에서는 noglob locate *foo*bar*을 쓰면 locate매개변수를 사용하여 호출합니다 *foo*bar*. 일반적으로 noglob별칭 뒤에 내장 기능을 숨깁니다. 이 기능은 수행하려는 작업과 관련이 없습니다.

답변2

언급한 방식으로 "해석되지 않은" 쉘 입력을 받을 수 없다는 점을 지적하는 다른 답변은 정확할 수 있지만 이 가능성을 단호하게 거부하는 것은 잘못된 것입니다. 쉘에 해석하지 말라고 지시하면 당연히 쉘이 해석하기 전에 수신할 수 있습니다. Simple POSIX를 사용하면 heredoc이 작업이 매우 쉬워집니다.

% sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<'_EOF_'     
> c:\some\stupid\windows\place
> _EOF_
/drive/c/some/stupid/windows/place

편집 1:

이러한 문자열을 쉘 매개변수로 쉘 함수에 전달하려면 이를 쉘 변수에 저장해야 합니다. 일반적으로 단순히 운이 좋지 않을 수는 없지만 var=<<'HEREDOC'POSIX는 내장 -r매개변수를 지정합니다 read.

% man read

POSIX 프로그래머 매뉴얼

...

기본적으로 백슬래시( '\' )는 -r 옵션이 지정되지 않는 한 이스케이프 문자(백슬래시)에 설명된 대로 이스케이프 문자로 작동해야 합니다. 표준 입력이 터미널 장치이고 호출하는 셸이 대화형인 경우 다음과 같은 경우 read에서 연속 행을 묻는 메시지가 표시됩니다.

  • -r 옵션을 지정하지 않으면 쉘은 백슬래시로 끝나는 입력 행을 읽습니다.

  • 여기서는 새 줄을 입력한 후에도 문서가 종료되지 않습니다.

결합하면 처음에는 직관적이지 않을 수도 있지만 사소하고 이식 가능합니다 read.heredoc

% _stupid_mspath_fix() { 
> sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_
>> ${1}
>> _EOF_
> }
% read -r _stupid_mspath_arg <<'_EOF_'                    
> c:\some\stupid\windows\place
> _EOF_
% _stupid_mspath_fix ${_stupid_mspath_arg}
/drive/c/some/stupid/windows/place

편집 2:

heredocs아마도 두 번째 예에서 둘 사이의 차이점을 발견했을 것입니다. heredoc _EOF_함수 내의 종결자는 인용되지 않은 반면, 입력 종결자는 read작은따옴표로 묶입니다. 이러한 방식으로 쉘은 heredoc인용되지 않은 종결자 쌍을 사용하여 확장을 수행하도록 지시되지만 종결자가 인용될 때는 그렇게 하지 않도록 지시됩니다. 함수에서 따옴표가 없는 내용을 확장할 때 heredoc확장하는 변수의 값이 이미 따옴표 붙은 문자열로 설정되어 있고 이를 두 번 구문 분석하지 않기 때문에 중단되지 않습니다.

아마도 당신이 원하는 것은 한 명령의 출력에서 ​​다른 명령의 입력으로 Windows 경로를 동적으로 전달하는 것입니다. 의 명령 대체를 통해 heredoc다음이 가능해집니다.

% _stupid_mspath_fix() { 
> sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_
>> ${1}
>> _EOF_
> }
% read -r _stupid_mspath_arg <<'_EOF_'                    
> c:\some\stupid\windows\place
> _EOF_
% _stupid_mspath_fix ${_stupid_mspath_arg}
/drive/c/some/stupid/windows/place    
% read -r _second_stupid_mspath_arg <<_EOF_                    
> $(printf ${_stupid_mspath_arg})
> _EOF_
% _stupid_mspath_fix ${_second_stupid_mspath_arg}
/drive/c/some/stupid/windows/place

따라서 기본적으로 하나의 응용 프로그램( printf위에서 사용한)에서 백슬래시를 안정적으로 출력할 수 있는 경우 해당 명령을 내부적으로 실행 $(...)하고 다른 응용 프로그램에 전달하면 heredoc백슬래시를 응용 프로그램(예: 위의 응용 프로그램)에 대한 인용 read되지 않은 sed. 백슬래시를 완전히 구문 분석하지 마세요. 애플리케이션이 백슬래시를 입력/출력으로 처리할 수 있는지 여부는 직접 알아내야 합니다.

질문과 엄격하게 관련이 없습니다.

Gilles의 답변에서 그는 ${var/search/replace}멋지지만 POSIX는 아닌 매개변수 확장 형식을 권장했습니다. 이것은 정말 굴욕적인 일입니다. 그것은 나에게 중요하지 않지만 그의 편집에서 그는 posix ()일부 사람들에게 오해의 소지가 있을 수 있는 함수 이름을 유지했습니다.

이 시점에서 원본 게시물의 posix ()함수는 매우 편리한 확장 정규식 sed -r인수를 사용하지만 불행히도 그것도 POSIX가 아닙니다. POSIX는 확장된 정규식 매개변수를 지정하지 않으므로 sed해당 사용이 신뢰할 수 없을 수 있습니다.

내 계정불과 며칠 전 Stack Overflow에 POSIX 매개변수 확장을 구체적으로 다루는 몇 가지 답변을 게시했습니다. POSIX 가이드를 참조하여 링크한 내 프로필 페이지에서 링크를 찾을 수 있습니다. 또한 내가 시연하는 다른 용도도 찾을 수 있습니다 heredoc. 예를 들어 전체 쉘 스크립트를 쉘 변수로 읽고 프로그래밍 방식으로 구문 분석하고 조작한 다음 마지막으로 다른 스크립트나 쉘 함수 내에서 새 버전을 실행하는 등의 작업을 수행합니다. 그냥 말하는 거야.

답변3

쉘 프로세스를 가질 수 없습니다"설명할 수 없는"입력. 명령줄에 입력하는 내용은 셸에서 해석되는 문자열일 뿐입니다. 셸에서 텍스트, 입력한 문자를 함수나 명령에 전달하도록 할 수 없습니다.가지다이를 해석하여 어떤 명령/함수를 호출하고 어떤 매개변수를 사용해야 하는지 알아보세요! 명령 프롬프트에 입력할 때 쉘의 해석 규칙에 따라 입력해야 한다는 점을 인정해야 합니다(쉘을 사용하고 있기 때문입니다!).

쉘 해석 규칙을 선택하는 것은 매우 유용합니다. 이는 방해가 되지 않지만 오히려 임의의 인수 지정을 포함하여 원하는 모든 작업을 수행하도록 셸에 지시하는 방법을 제공합니다. 해석이 없으면 쉘은 입력에서 수행할 정확한 작업을 추출할 수 없습니다. 해석은 이스케이프 없이 명령에 전달할 수 없는 특수 문자(예: 공백)를 의미합니다.

설명 자체에 관해서는 항상 찾았습니다.배쉬 문서이것은 매우 좋습니다. 즉, 물결표 확장과 같은 일은 매우 초기에 발생합니다(그리고 물결표 확장은 특정 상황에서만 발생합니다). 그런 다음 변수 대체 및 토큰화가 발생하고 마지막으로 와일드카드가 발생합니다.

관련 정보