방법 1

방법 1

X 세션 내에서 다음 단계를 수행할 수 있습니다.

  1. 터미널 에뮬레이터(Xterm)를 엽니다.
    • Bash는 읽고 .bashrc대화형이 됩니다. 명령 프롬프트가 명령을 기다리고 있습니다.
  2. 입력하다 vim 'my|file*' '!another file&'.
    • Vim이 시작되고, 표시되고 my|file*, !another file&편집됩니다.
  3. 에 따르면 CTRL-Z.
    • Vim이 정지되고 Bash 프롬프트가 다시 나타납니다.

난 이해가 안 돼요대본3단계(작업 제어)를 포기하지 않고 1단계와 2단계를 수행합니다. 파일을 매개변수로 수신합니다.

script 'my|file*' '!another file&'

도와주세요?

스크립트는 선택한 텍스트 파일을 인수로 제공하여 파일 관리자에 의해 실행됩니다.

걱정하지 마세요. 저는 합리적이고 일반적으로 파일 이름을 그런 식으로 지정하지 않습니다. 반면, *!&|$<newline>...파일 이름에 특수 문자( )가 나타나는 경우 스크립트가 중단되어서는 안 됩니다.

나는 구체적인 예를 들기 위해 Vim을 사용하고 있습니다. 터미널에서 대화형으로 실행되고 인수를 받는 다른 프로그램은 이 솔루션의 이점을 누릴 수 있습니다.


나의 시도/연구

xterm -e vim "$@"

분명히 실패했습니다. Xterm에는 쉘이 없습니다.

Supershell로 즉시 돌아가지 않고 초기 명령을 사용하여 대화형 bash 하위 쉘을 실행합니다. 유망해 보입니다. 거기에 대한 답변은 .bashrcBash의 소스로 (대신) 다른 파일을 지정하는 방법을 설명합니다 . 그래서 나는 이것을 만들었습니다 ~/.vimbashrc:

. ~/.bashrc
set -m
vim

이제 전화해 보세요

xterm -e bash --init-file ~/.vimbashrc

그 결과 Bash와 일시 중단 가능한 Vim이 포함된 새로운 터미널이 탄생했습니다. 하지만 Vim이 열어야 할 파일을 지정하는 방법을 알 수 없습니다.

답변1

나는 몇 가지 접근법을 생각할 수 있는데, 첫 번째 접근법은 Bash에서 덜 진부하다고 생각합니다. 주로 (나에게) 다루기 더 쉬운 특이한 점이 있는 것 같기 때문입니다. 하지만 이것도 취향의 문제일 수 있으므로 두 가지 모두 다루겠습니다.

방법 1

"사전 참조" 방법

만드는 것도 포함된다당신의 스크립트$@내부 상호 작용을 대신하여 이 작업을 수행하기 위해 배열을 확장하고 파일 시스템의 파일 설명자 기능(시스템에서 사용 가능한 경우)을 인수로 bash사용할 수 있습니다 . 이러한 파일 설명자는 다음과 같이 파일 이름을 처리할 문자열을 참조할 수 있습니다./dev/fd/X--init-file

xterm -e bash --init-file /dev/fd/3 3<<<". ~/.bashrc; set -m; vim $@"

파일 시스템에 대한 이 파일 설명자 트릭의 한 가지 장점은 사용자와 같은 외부 도우미 파일에 의존하지 않기 때문에 자체 포함된 솔루션이 있다는 것입니다 . 이는 확장으로 인해 콘텐츠가 동적이기 .vimbashrc때문에 여기서 특히 편리합니다 .--init-file$@

반면에 스크립트에서 내부 셸까지 파일 설명자의 실제 지속성에 주의가 필요할 수 있습니다. 이 트릭은 개입하는 프로세스가 상위 프로세스로부터 받은 파일 설명자를 닫지 않는 한 잘 작동합니다. 이는 많은 표준 도구의 일반적인 동작이지만 sudo수신된 모든 파일 설명자를 닫는 기본 동작의 중간에 있는 경우 이 트릭은 작동하지 않으며 임시 파일이나 원시 파일을 사용해야 합니다 .vimbashrc.

어쨌든 $@위의 접근 방식을 사용하면 파일 이름에 공백이나 개행 문자가 포함된 경우에는 작동하지 않습니다. 내부적으로 bash이러한 파일 이름은 명령 시퀀스를 사용할 때 인용되지 않으므로 파일 이름의 공백은 표준 해석에 따라 단어 구분 기호로 작동하기 때문입니다.

@Q$@이 문제를 해결하기 위해 Bash 4.4 이상에서는 다음과 같이 배열에 매개변수 변환 구문을 사용하면 됩니다 .

xterm -e bash --init-file /dev/fd/3 3<<<". ~/.bashrc; set -m; vim ${@@Q}"

Bash 4.4 이하 버전에서는 다음과 같이 이것을 사용하여 동일한 결과를 얻을 수 있습니다 printf %q(더 나은 가독성을 위해 Here Document로 사용하지만 위의 Here String과 동일한 작업을 수행함).

printf -v files ' %q' "$@"
xterm -e bash --init-file /dev/fd/3 3<<EOF
. ~/.bashrc
set -m
vim $files
EOF

그런데 설정에 따라 대화형 쉘에 대한 Bash의 표준 동작이므로 /etc/bash.bashrc사용자보다 먼저 소싱하는 것을 고려할 수도 있습니다 ..bashrc

또한 해당 명령은 원본 스크립트에 익숙하지 않고 무해하기 때문에 실제로 중복되지만 상호 작용이 암시되기 set -m때문에 여기서는 실제로 중복됩니다 . 즉 , 문자 그대로 질문 제목을 이해한다면 작업 제어 셸을 원할 것입니다. , 그러나 완전한 대화형 셸은 아니므로 필요합니다. 가지다--init-filebash-m행동 차이.

방법 2

-s옵션

Bash(및 POSIX) -s옵션을 사용하면 비대화형 과 마찬가지로 대화형 쉘에 대한 인수를 지정할 수 있습니다1 . 따라서 이 옵션을 독립형 솔루션으로 사용하면 -s다음과 같습니다.

xterm -e bash --init-file /dev/fd/3 -s "$@" 3<<'EOF'
. ~/.bashrc
set -m  # superfluous as bash is run with `--init-file`; you would instead need it for a job-controlling yet "non-interactive" bash (ie no `--init-file` nor `-i` option)
exec <<<'exec < /dev/tty; vim "$@"'
EOF

주목해야 할 이상한 점:

  1. Here 문서의 구분 기호 사양~ 해야 하다작은따옴표로 묶어야 합니다. 그렇지 않으면 여기 문서 내부 섹션이 해당 스크립트가 속한 내부 항목 $@이 아닌 스크립트(적절한 인용부호 등 없이)에 의해 확장됩니다 . bash이는 여기서 문서의 구분 기호를 의도적으로 인용하지 않는 "사전 인용" 접근 방식과 대조됩니다.
  2. 여기 문자열( exec <<<...표준 입력 리디렉션 부분)~ 해야 하다또한 작은따옴표 유형 2 또는 배열이 아직 채워지지 않은 경우 "$@"일부가 내부적으로 확장됩니다.bash$@
  3.  특히, 배열을 완전히 채워야 하는 명령의 실행을 exec <<<내부적으로 "지연"하려면 도우미로서 표준 입력 리디렉션(여기서 문자열을 통한 리디렉션)이 필요합니다.bash$@
  4. 이러한 도우미 stdin 리디렉션(Here String 섹션)에서는 bash내부 리디렉션을 자체 stdin으로 다시 만들어야 합니다. 이번에는 제어 터미널(따라서 이 exec < /dev/tty줄)로 돌아가서 대화형 기능을 다시 시작할 수 있도록 해야 합니다.
  5. 우리는해야합니다모두주문하다의미는지정된 이후에 실행 exec < /dev/tty(예: 여기)vim "$@"같은 줄에3exec < /dev/tty 이러한 리디렉션 후에는 여기서 문자열 4를 더 이상 읽을 수 없기 때문입니다 . 실제로 이 특정 코드 조각이 이 예와 같이 충분히 짧다면 Here String으로 사용하는 것이 더 좋을 것입니다.

이 접근 방식은 아마도 여러분과 같은 외부 도우미 파일과 함께 사용하는 데 더 적합할 것입니다 .vimbashrc(비록 독립 실행형의 편리함은 포기하지만). 왜냐하면 그러한 파일의 내용은 파일 이름 매개 변수 문제에 관한 한 완전히 정적일 수 있기 때문입니다. 이렇게 하면 파일 관리자가 호출하는 스크립트는 다음과 같이 간단해집니다.

xterm -e bash --init-file .vimbashrc -s "$@"

그 동반자는 .vimbashrc다음과 같습니다:

. ~/.bashrc
#  (let's do away with the superfluous `set -m`)
exec <<<'exec < /dev/tty && vim "$@"'  # let's also run vim only if the redirection to the controlling tty succeeded

동반 파일에는 여전히 몇 가지 단점이 있지만 "정리" 고려 사항을 제외하고 후자 버전(독립 실행형이 아님)의 가능한 장점 중 하나는 전체 xterm -e ...명령(part 제외 "$@")을 파일 관리자가 직접 사용할 수 있다는 것입니다. " 스크립트",만약에매우 훌륭하게 명령을 지정할 수 있으며 파일 이름 인수와 함께 정식 "argv" 배열을 생성하기 위해 공손하게 공백으로 분할됩니다.

-s또한 모든 버전의 전체 메소드가 기본적 .bash_history으로 사용됩니다.돕는 사람stdin 리디렉션이 있기 때문에 해당 특정 부분을 가능한 한 오랫동안 유지해 왔습니다. 물론 unset HISTFILE.--init-file

--

비교하자면, 환경 변수 에 의해 지정된 스크립트 배열이 채워지기 dash때문에 이 방법을 사용하는 것이 더 편리하므로 독립형 솔루션은 매우 간단합니다.dash$@ENV

xterm -e env ENV=/dev/fd/3 dash -s "$@" 3<<'EOF'  # `dash` run through `env` just to be positive that `ENV` is present when dash starts
vim "$@"
EOF

화타이


1옵션을 사용하여 셸을 호출할 때와 달리 지정할 수 없다는 점은 예외 입니다.$0-c

2 여기에 추가 문서를 사용하는 경우 해당 구분 기호도 인용해야 합니다.

3은 실제로 동일한 "complete_command"에 있습니다.POSIX에 의해 정의됨즉, 동일한 "complete_command"의 일부인 한 여러 줄에 걸쳐 있을 수 있습니다(예: 줄에 줄 연속 백슬래시가 있거나 복합 블록 안에 있는 경우).

4 이것은 아마도 첫 번째 짧은 단락에서 파생된 표준 동작이어야 합니다.이 구역

답변2

간단한 개념 증명으로 다음을 시도했습니다.

. ~/.bashrc
set -m
vim $arg

그리고:

arg=file-to-edit xterm -e bash --init-file vimbashrc

이는 사용자가 지정하는 대로 어느 정도 작동하며 대화형 명령에 인수를 전달할 수 있습니다.

따라서 임시 파일을 사용하면 다음과 같은 결과가 발생할 수 있습니다.

#!/bin/bash

if [ "$1" = "" ] ; then
        . ~/.bashrc
        set -m
        (IFS=$'\n'; vi $(cat "$tmpfile"))
else
    tmpfile=$(mktemp /tmp/vimstart.XXXXXX)
    for arg in "$@" ; do
        echo "$arg" >> $tmpfile
    done
    tmpfile=$tmpfile xterm -e bash --init-file ./vimstart
    rm "$tmpfile"
fi

파일 이름에 가 포함될 수 있으므로 \nNULL 문자를 구분 기호로 사용할 수도 있습니다.

#!/bin/bash

if [ "$1" = "" ] ; then
    . ~/.bashrc
    set -m
    (IFS=$'\00'; vi $(cat "$tmpfile"))
else
    tmpfile=$(mktemp /tmp/vimstart.XXXXXX)
    for arg in "$@" ; do
        echo -n "$arg" >> $tmpfile
                echo -n $'\x00' >> $tmpfile
    done
    tmpfile=$tmpfile xterm -e bash --init-file ./vimstart
    rm "$tmpfile"
fi

관련 정보