명령 대체를 실행할 때 덜 표시되는 이유는 무엇입니까?

명령 대체를 실행할 때 덜 표시되는 이유는 무엇입니까?

cd상위 프로세스에서 사용되는 경로를 반환하는 대화형 스크립트가 있습니다. 이와 같이:

$ cd $(myscript)

스크립트를 실행하는 동안 을 사용하고 싶습니다 less. 불행하게도 명령 대체 중에는 을 사용하는 것이 less작동하지 않는 것 같습니다.

$ echo $(less <<< 'some text') # Not working
some text

그래서 제 질문은: 왜 작동하지 않나요? 해결책이 있나요?

스크립트 실행 중에 대화형 도움말 화면을 표시하려고 합니다. 이 스크립트를 명령 대체에 넣어야 합니다. 왜냐하면 그것이 상위 프로세스에서 생성된 경로로 CD를 이동할 수 있는 유일한 방법이기 때문입니다. 더 좋은 방법이 있을 수도 있지만 이것이 최선의 선택입니다.

답변1

일반적 echo $(somecmd)으로 모든 somecmd.의 경우 출력은 somecmd의 인수로 확장된 echo다음 echo해당 인수를 가져와 출력에 인쇄합니다. 일반적으로 직접 실행할 수 있습니다 somecmd.

단어 분리기와 와일드카드라는 두 가지 차이점은 일반적입니다. echo $(somecmd)공백을 압축하고 파일 이름 glob( )처럼 보이는 모든 항목을 확장합니다 *.txt. 그러나 물론 이것은 그냥 실행 somecmd하거나 echo "$(somecmd)"따옴표로 실행할 때는 발생하지 않습니다.저것마지막 개행 문자를 제외한 모든 항목을 제거합니다. 확장된 백슬래시 가 이스케이프 echo될 수도 있습니다 .

less의 목적은 다음 과 같습니다 .인터렉티브파일을 찾아보거나 터미널이 거의 필요한 파이프 입력을 수행합니다. 명령 대체에서 실행하면 less의 출력이 파이프에 연결되고 해당 동작이 cat.(맨 페이지에서 정확한 동작에 대한 언급을 찾을 수 없는 것 같습니다.)


이제 명령 대체에서 실행되고 사용자가 일부 출력을 찾아볼 수 있도록 허용하고 여전히 명령 대체를 통해 다른 텍스트를 반환하는 스크립트가 필요한 경우 리디렉션을 창의적으로 사용할 수 있습니다(mosvy의 설명 설명).

$ cat myscript
#!/bin/bash
echo this is the output

cat >&2 <<EOF
you can
browse this
with less
EOF
$ foo=$( ./myscript 2> >(less > /dev/tty))

스크립트의 표준 출력은 명령 대체로 이동하고 오류 출력은 으로 설정되므로 lessfoo설정됩니다 this is the output. foo적어도 .less

또한 이러한 실행은 less작업 제어를 혼란스럽게 하므로 실행 중에 Ctrl-C를 누르면 이상한 동작 등이 발생할 수 있습니다.


여기서는 임시 파일을 사용하는 것이 좋습니다. 결과를 매개변수(예: ) myscript라는 파일에 쓰고 다음을 실행합니다.echo "$result" > "$1"

tmp=$(mktemp)
myscript "$tmp"
cd "$(cat "$tmp")"
rm "$tmp"

또는 이제 다른 대화형 프로그램을 myscript일반적인 방식으로 시작할 수 less있으며 작업 제어에 문제가 없어야 합니다.

답변2

(trap : INT; echo "$(less <<< 'some text' >/dev/tty; echo done)")

lesscat명령 대체(표준 출력이 파이프인 경우)에 사용될 때와 같이 표준 출력이 tty가 아닌 경우에는 뭔가 (비)멋지게 됩니다[1].

대화형 bash에서 테스트할 때(작업 제어는 기본적으로 활성화되어 있음) (...)서브셸은 명령이 터미널에서 올바른 포그라운드 작업의 일부로 실행되는지 확인합니다 . 그렇지 않으면 다음 명령을 사용하여 작업을 일시 중지 하고 종료하는 것이 less불가능할 수 있습니다. 잘못된 행동은 다른 방식으로 발생합니다[2].^Z^C

이렇게 하면 trap : INT서브셸이 a를 무시 ^C하고 해당 구성을 해당 서브셸에 전달하지 않게 됩니다.

명령이 쉘 스크립트의 일부인 경우 모든 프로세스는 동일한 프로세스 그룹/작업의 일부로 실행되지만 (...)트랩의 범위를 제한하는 것은 여전히 ​​유용할 수 있습니다 INT.

[1] 표준 출력이 tty가 아닌 경우 멋지게 이스케이프된 바이너리 데이터를 인쇄하는 데 사용할 수도 없습니다.

$ printf '\xee' | less -FXR
<EE>
$ printf '\xee' | less -FXR | cat
�$ 

[2] 일어날 수 있는 일이 많으며 모두 나쁘다. 예를 들어,

$ ls -d $(less <<<'some text' >/dev/tty; pwd)

bash별도의 프로세스를 포크하여 바이너리를 실행하고 프로세스 교체를 하위 프로세스로 ls실행합니다 .$(...)앞으로별도의 프로세스 그룹/작업으로 이동하고 바이너리를 실행합니다.

^Z안쪽을 누르면 less정상적으로 처리되지만 less중지할 수 없거나(쉘과 해당 less작업이 세션 리더인 경우) 중지하기만 하고 less상위 프로세스는 중지하지 않습니다.

^Cinside 를 누르면 less포착되어 처리되지만 lessa 도 메인 쉘(터미널의 포그라운드 작업)로 전송되어 bash의 readline 및 race SIGINT뿐만 아니라 다음 프롬프트로 돌아가게 됩니다. less터미널 속성 변경은 서로를 인식하지 못하여 완전한 혼란을 초래합니다.

노트

이 모든 내용은 다음에 적용됩니다.어느프로그램은 예제뿐만 아니라 명령 대체를 통해 실행됩니다 $(less ...).

$ cat >foo <<'EOT'; chmod 755 foo
t=$(mktemp)
vi "$t" </dev/tty >/dev/tty 2>&1
echo "$t"
EOT
$ cat $(./foo)
# ^Z doesn't work in vi

관련 정보