다루기 힘든

다루기 힘든

Android( mkshMirBSD Korn Shell 사용)에는 특별한 문자열 대체 구문("값 대체"라고 함)이 있습니다.

${|commands}

명령의 출력(예: ``sum )을 수집하는 대신 대체 결과는 구분 기호 내에 할당된 변수에서 가져옵니다 $(). $REPLY그것을 특별하게 만드는 것은 명령입니다원하지 않는다서브셸에서 실행 - 동일한 셸에서 실행되며 현재 셸 세션이 소유한 모든 것에 액세스할 수 있습니다.

mksh데비안에는 Android와 똑같이 동작하는 MirBSD Korn Shell용 패키지가 있습니다 .

유사한 구문을 지원하는 쉘은 다음과 같습니다.

  • 명령은 상위 쉘과 동일한 쉘에서 실행됩니다.
  • 교체 결과는 파일 설명자가 아닌 다른 것에서 얻습니다.
    • 출력이나 배관을 읽는 것이 FD로 계산된다는 것을 쉽게 알 수 있습니다.

답변1

이 함수는가치 대체또는발섭저자: Thorsten Glaser(a.k.a.@미라빌로스), 관리자 또는 MirBSD 및 해당 쉘 mksh(pdksh에서 파생됨), mksh.

그것은2013년 5월 2일 mksh 코드 기반에 합류하겠다는 약속, 그리고 다음날 mksh 메일링 리스트에 R46 버전을 출시했습니다.

${ body; }명령 대체 양식('이라고 함) 뒷면에 적혀 있습니다.기능적 대체또는흥미로운 잠수함(가운데 mksh)는 같은 해 2월 ksh93에서 복사되어 R46에 출시되었습니다.

ksh93에서는 내장 I/O가 가상화됩니다. 분기나 I/O $(builin-cmd)가 포함되지 않습니다 . ${ builtin-cmd; }따라서 fd를 포함하지 않는 연산자에 대한 요구 사항을 충족하도록 $(print foo)여전히 ${ print foo; }확장 됩니다.foo

두 형식 모두 print내장 함수는 fd에 아무 것도 쓰지 않지만 가능한 출력(후행 줄 바꿈 제거)은 확장을 구성합니다. 둘 사이의 차이점은 $(...)서브쉘 환경이 도입되는 반면(다른 쉘과 달리 하위 프로세스를 포크하여 달성되지 않음) 서브쉘 환경은 ${ ...; }도입되지 않는다는 것입니다.

이제 ksh93(1983년부터 ksh를 거의 처음부터 다시 작성함)으로 이 작업을 수행하려면 쉘의 모든 I/O를 구체적으로 다시 작성해야 했습니다. mksh가 ${ ...; }2013년에 이 기능을 추가했을 때 삭제된 임시 파일에 출력을 기록하고 확장을 보완하기 위해 코드가 반환된 후 해당 파일의 내용을 읽는 더 간단한 접근 방식을 취했습니다.

그러나 이는 출력이 임시적으로라도 디스크에 저장된다는 것을 의미하며 I/O는 결과 데이터가 ksh93처럼 메모리에서 전달되는 경우보다 성능이 저하된다는 것을 의미합니다. 그래서 Thorsten이 전용 변수( )를 사용하여 값을 전달할 수 있고 쉘 내부에 큰 수정이 필요하지 않은 ${| ...; }별도의 양식을 추가한 이유가 아닐까 싶습니다 .$REPLY

그러나 이는 이러한 방식으로 사용되는 함수가 해당 값을 반환하기 위해 특별히 작성되어야 함을 의미하며 $REPLY(목록이 아닌 스칼라만 될 수 있는 분할+글로브를 통한 경우 제외) 이는 단지 구문상의 설탕이 될 뿐입니다. 예:

sanitize() {
  REPLY=${1//[!0123456789-]}
  local sign=
  case $REPLY in
    (-*) REPLY=${REPLY#-}; sign=-
  esac
  REPLY=$sign${REPLY//-}
}

print "$(( ${|sanitize "$1"} + ${|sanitize "$2"} ))"

그것이 없으면 다음과 같이 작성해야 합니다.

sanitize "$1"; a=$REPLY
sanitize "$2"; b=$REPLY
print "$(( a + b ))"

$(...)및 에 비해 한 가지 장점은 ${ ...; }후행 개행 문자를 제거하지 않는다는 것입니다. 예를 들어 는 개행 문자로 끝나면 작동하지 않기 때문에 잘못된 $(basename -- "$file")반면, while(함수에서 기본 이름을 반환하는 함수로 재정의되었다고 가정)에는 문제가 없습니다.$file${|basename -- "$file"}basename$REPLY

I/O를 포함하지 않고 값을 반환할 수 있는 구조를 가진 다른 쉘:

다루기 힘든

실제로 2019년에 mksh의 valsub의 단순화된 버전을 구현하겠다는 제안이 있습니다.결국 진화했다이 제안, 하지만 제가 아는 한 아직 성공하지 못했습니다 zsh.

2024년편집 mksh ${|...}및 ksh93은 ${...;}이제 zsh에서 구현됩니다.6.0 또는 5.9 이후의 다음 릴리스에서 사용할 수 있을 것으로 예상됩니다. ${|var|...}가 아닌 다른 변수에 값을 반환할 수 있는 변형 도 있습니다 $REPLY.

그러나 zsh에는 하위 쉘이나 I/O를 포함하지 않고 임의 코드의 결과로 확장할 수 있는 몇 가지 대안이 있습니다.

수학 함수

산수에는 zsh이런 개념이 있습니다.수학 함수:

square() (( $1 * $1))
functions -M square 1

echo $(( square(5) + square(12) ))

그러나 이는 숫자(정수 또는 부동 소수점 숫자)로 제한되며 산술 표현식에만 사용할 수 있습니다. 수학 함수 자체는 functions -sM)를 사용하여 숫자가 아닌 값을 인수로 사용할 수 있으므로 꽤 복잡하더라도 다음과 같이 할 수 있습니다.

func() REPLY=foo$1; functions -sM func

echo ${$((func(bar)))+$REPLY} ${$((func(baz)))+$REPLY}

다음 mksh과 동일:

func() REPLY=foo$1

echo "${|func bar}" "${|func baz}"

동적으로 이름이 지정된 디렉터리

zshI/O 없이 쉘 코드를 사용하여 계산할 수 있는 또 다른 형태의 확장이 있습니다. 물결표 확장이라는 사용자 정의 프레임워크를 사용하고 있습니다.동적으로 이름이 지정된 디렉터리(바라보다 info zsh dynamic).

정의하는 경우:

autoload -Uz add-zsh-hook

valsub() {
  [[ $1 = n && $2 = '!'* ]] && eval "${2#?}" && reply=("$REPLY")
}
add-zsh-hook -Uz zsh_directory_name valsub

~[!'REPLY=something']그러면 해당 양식의 물결표 확장이 something.

물결표 확장이 모든 경우에 수행되는 것은 아니지만 사용할 수도 있습니다.동적으로 이름이 지정된 디렉터리매개변수 확장의 일부로 이 기능을 사용하십시오.위에서 언급한 valsub 지원에 대한 논의에 기술이 설명되어 있습니다..

e 및 + 전역 한정자

Glob은 다음 명령을 사용하여 임의 코드의 결과로 확장될 수도 있습니다 e(예:평가하다) 또는 +글로벌 한정자.

이는 특정 코드의 결과를 기반으로 파일을 필터링하는 데 자주 사용됩니다.

좋다:

ls -ld -- *.txt(e['(( $#REPLY > 20 ))'])

20자보다 긴 txt 파일 이름을 선택하려면 그러나 확장 결과를 변경하는 데에도 사용할 수 있습니다.

ls -ld -- *.txt(e['REPLY=$REPLY:r.html'])

( txt확장자를 로 바꾼 파일로 확장합니다 html.) 심지어:

ls -ld -- *.txt(e['reply+=($REPLY:r.html)'])

반환 txt하고 html번역하세요.

따라서 실제로 다음을 수행할 수 있습니다.

echo /(e['REPLY=foobar'])

이를 임의 코드의 결과로 확장하기 위해 우리가 알고 있는 한정자가 항상 여기에 적용됩니다 /. 아니면 목록도 가능합니다:

printf '<%s>\n' /(e['reply=(foo bar)'])

한정자 +는 함수 이름만 허용하는 변형이므로 확장이 생성되는 함수를 수행할 수 있습니다 echo /(+func).func

또한 ~확장과 마찬가지로 와일드카드가 모든 경우에 수행되는 것은 아닙니다.

영어

esByron Rakitzis의 Research Unix V10/Plan9 셸 rc의 공개 도메인 복제본의 파생물입니다 .

rc이 함수는 종료 상태 목록(신호 이름 또는 양의 정수일 수 있음)을 반환하고 $status목록 변수에서 호출자가 사용할 수 있도록 할 수 있습니다.

es무엇이든 목록을 반환할 수 있도록 이것을 확장하고 에서 사용할 수 있게 만드는 대신 $status구문을 사용하여 종료 상태(또는 함수 반환 값)를 가져옵니다 <={...}.

그래서 당신은 이것을 할 수 있습니다 :

fn foo { return foo$1 }
echo <={foo bar}

예를 들어.

하지만 빈 목록 또는 모든 요소가 비어 있거나 0인 목록으로 구성된 반환 값만 다음과 같이 해석된다는 점에 유의하세요.성공적인. 예를 들어, 여기서는 항상 다음과 같이 해석되지 않는 값을 반환하므로 foo anything && echo bar출력되지 않습니다 .barfoo성공.

크쉬 93

$(...)이미 설명한 이 기능 외에도 ${ ...; }I/O를 사용하지 않고도 확장이 동적 콘텐츠를 가질 수 있도록 하는 기능이 있습니다.

주제

변수가 설정되거나 확장될 때마다 호출되는 함수를 정의할 수 있습니다. 연관 배열 변수의 경우 이러한 함수는 아래 첨자에 액세스할 수 있으므로 이를 사용하여 함수에 임의 인수를 전달할 수 있습니다.

typeset -A valsub
function valsub.get {
  .sh.value=foo${.sh.subscript}
}
echo "${valsub[bar]}"

출력됩니다 foobar.

수학 함수

ksh93에는 수학 함수도 있지만 구문은 다음 함수와 다릅니다 zsh.

function .sh.math.square x {((.sh.value = x*x))}
echo "$(( square(5) + square(12) ))"

답변2

실제 질문에 대답하려면: 아니요. 다른 쉘에는 이것이 없습니다.

MirBSD Korn 쉘 변경 로그에 따르면,가치 대체Thomas Goirand가 2014년 버전 46에 추가했습니다.

내가 아는 한, 당시나 그 이후로 이 아이디어를 복제한 다른 ​​쉘은 없습니다. 그들 중 일부는 대안을 중요하게 생각합니다~에서, 그러나 실제로는 가치 대체물이 아닙니다.

답변3

${ cmds;}ksh93의 명령 대체 형식은 동일한 셸에서 실행되지만 cmds일반 명령 대체와 마찬가지로 표준 출력을 캡처합니다. 예:

a=1; echo ${ a=2; echo wtf;}; echo $a
wtf
2

명령의 표준 출력을 캡처한다는 사실은 다음과 같습니다.정확히출력을 임시 파일에 저장한 다음 다시 읽을 필요가 없고 명명된 파이프를 설정하거나 일부 털이 많은 함수를 재정의하여 출력을 그냥 변수가 아닌 일부 변수에 추가할 필요가 없기 때문에 이것이 무슨 소용이 있습니까? 그냥 적어보세요.

이는 "값 대체" mksh 기능과 매우 다르며 그 이유를 찾을 수 없습니다. 왜 REPLY변수를 먼저 할당한 다음 이를 로 사용할 수 없습니까 $REPLY?

관련 정보