X 세션 내에서 다음 단계를 수행할 수 있습니다.
- 터미널 에뮬레이터(Xterm)를 엽니다.
- Bash는 읽고
.bashrc
대화형이 됩니다. 명령 프롬프트가 명령을 기다리고 있습니다.
- Bash는 읽고
- 입력하다
vim 'my|file*' '!another file&'
.- Vim이 시작되고, 표시되고
my|file*
,!another file&
편집됩니다.
- Vim이 시작되고, 표시되고
- 에 따르면 CTRL-Z.
- Vim이 정지되고 Bash 프롬프트가 다시 나타납니다.
난 이해가 안 돼요대본3단계(작업 제어)를 포기하지 않고 1단계와 2단계를 수행합니다. 파일을 매개변수로 수신합니다.
script 'my|file*' '!another file&'
도와주세요?
스크립트는 선택한 텍스트 파일을 인수로 제공하여 파일 관리자에 의해 실행됩니다.
걱정하지 마세요. 저는 합리적이고 일반적으로 파일 이름을 그런 식으로 지정하지 않습니다. 반면, *!&|$<newline>...
파일 이름에 특수 문자( )가 나타나는 경우 스크립트가 중단되어서는 안 됩니다.
나는 구체적인 예를 들기 위해 Vim을 사용하고 있습니다. 터미널에서 대화형으로 실행되고 인수를 받는 다른 프로그램은 이 솔루션의 이점을 누릴 수 있습니다.
나의 시도/연구
xterm -e vim "$@"
분명히 실패했습니다. Xterm에는 쉘이 없습니다.
Supershell로 즉시 돌아가지 않고 초기 명령을 사용하여 대화형 bash 하위 쉘을 실행합니다.
유망해 보입니다. 거기에 대한 답변은 .bashrc
Bash의 소스로 (대신) 다른 파일을 지정하는 방법을 설명합니다 . 그래서 나는 이것을 만들었습니다 ~/.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-file
bash
-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
주목해야 할 이상한 점:
- Here 문서의 구분 기호 사양~ 해야 하다작은따옴표로 묶어야 합니다. 그렇지 않으면 여기 문서 내부 섹션이 해당 스크립트가 속한 내부 항목
$@
이 아닌 스크립트(적절한 인용부호 등 없이)에 의해 확장됩니다 .bash
이는 여기서 문서의 구분 기호를 의도적으로 인용하지 않는 "사전 인용" 접근 방식과 대조됩니다. - 여기 문자열(
exec <<<...
표준 입력 리디렉션 부분)~ 해야 하다또한 작은따옴표 유형 2 또는 배열이 아직 채워지지 않은 경우"$@"
일부가 내부적으로 확장됩니다.bash
$@
- 특히, 배열을 완전히 채워야 하는 명령의 실행을
exec <<<
내부적으로 "지연"하려면 도우미로서 표준 입력 리디렉션(여기서 문자열을 통한 리디렉션)이 필요합니다.bash
$@
- 이러한 도우미 stdin 리디렉션(Here String 섹션)에서는
bash
내부 리디렉션을 자체 stdin으로 다시 만들어야 합니다. 이번에는 제어 터미널(따라서 이exec < /dev/tty
줄)로 돌아가서 대화형 기능을 다시 시작할 수 있도록 해야 합니다. - 우리는해야합니다모두주문하다의미는지정된 이후에 실행
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
파일 이름에 가 포함될 수 있으므로 \n
NULL 문자를 구분 기호로 사용할 수도 있습니다.
#!/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