xargs 및 vi- "입력이 터미널에서 아닙니다"


14

php.ini내 시스템에 약 10 개의 파일이 있으며, 여기저기서 빠르게 찾아보고 싶었습니다. 나는이 명령을 시도했다 :

locate php.ini | xargs vi

그러나 vi경고 Input is not from a terminal나면 콘솔이 정말로 이상해지기 시작합니다. 그런 다음을 눌러 :q!종료 vi한 다음 ssh 세션에서 연결을 끊고 콘솔이 다시 정상적으로 작동하도록 다시 연결해야합니다.

나는 여기서 일어나는 일을 이해한다고 생각합니다. 기본적으로 명령이 vi시작 되었을 때 완료되지 않았 으므로 명령이 완료 vi되지 않았을 수도 있고 터미널이 정상 모드에 있다고 생각하지 않습니다.

나는 그것을 고치는 방법을 모른다. 나는 운이 좋지 않은 Google과 unix.stackexchange.com을 검색했습니다.



참고로 reset터미널이 망가 졌을 때 터미널을 재설정하기 위해 실행할 수 있습니다 (ssh 세션에서 연결을 끊지 않아도 됨).
wisbucky

답변:


12
vi $(locate php.ini)

참고 : 파일 경로에 공백이 있으면 문제가 있지만 기능적으로는 명령과 같습니다.
이 다음 버전은 공백을 올바르게 처리하지만 조금 더 복잡합니다 (파일 이름의 줄 바꿈은 여전히 ​​나타납니다)

(IFS=$'\n'; vi $(locate php.ini))


설명:

무슨 일이 일어나고 있는지 프로그램은 파일 설명자를 생성 한 프로세스에서 상속합니다. xargsSTDIN이의 STDOUT에 연결되어 locate있으므로 vi원래 STDIN이 실제로 무엇인지 알 수 없습니다.


2
xargs는 제가 가장 좋아하는 도구 중 하나입니다. 데이터 피드 이외의 용도로 stdin을 사용하는 프로그램에는 적합하지 않습니다. 나는 당신의 답변과 그 이외의 설명을 좋아합니다. 어쨌든 +1 :)
cas

@CraigSanders 나는 그것을 남용하기 (부적절하게 사용하기)가 너무 쉬워 결국 그것을 좋아하지 않기 때문에 그것을 좋아하지 않습니다. 나는 xargs쉘 (또는 find)으로 직접 수행 할 수 없었던 절대적으로 사용해야했던 것에 빠지지 않았습니다 . 그러나 최선의 해결책이 될 수있는 경우를 생각할 수 있습니다. 그래서, 당신 xargs이하고있는 일, 인수를 나누는 방법, 프로그램을 실행하는 방법 등을 올바르게 사용하고있는 한, 그것을 위해 가고 싶습니다 :-P
Patrick

... | awk '{print $3}' | xargs | sed -e 's/ /+/g' | bc(필드 3의 모든 값을 더하기 위해) 같은 것을 이길 수는 없습니다 . 또는 sed -e 's/ /|/g'정규 표현식을 구성합니다. 예, 다른 도구와 마찬가지로 도구 사용법과 제한 사항 및주의 사항을 알아야합니다.
cas

vi $(...)방법은 이외의 쉘에서 와일드 카드에 문제가 zsh있습니다.
Stéphane Chazelas

또한 xargs공백 문제 옆 의 접근 방식에서는 작은 따옴표, 큰 따옴표 및 백 슬래시가있는 파일 이름도 문제가됩니다.
Stéphane Chazelas

10

이 질문은 이전에 슈퍼 유저 포럼 에서 요청되었습니다 .

해당 질문에 대한 @grawity의 답변에서 인용 :

xargs를 통해 프로그램을 호출하면 프로그램의 표준 입력 (표준 입력)이 / dev / null을 가리 킵니다. (xargs는 원래 stdin을 알지 못하므로 다음으로 가장 좋습니다.)

Vim은 stdin이 제어 터미널과 동일 할 것으로 기대하고 stdin에서 다양한 터미널 관련 ioctl을 직접 수행합니다. / dev / null (또는 tty가 아닌 파일 디스크립터)에서 수행되면 해당 ioctl은 의미가 없으며 ENOTTY를 리턴하며 자동으로 무시됩니다.

이것은 xarg의 매뉴얼 페이지에서 언급됩니다. OSX / BSD에서 :

-o 명령을 실행하기 전에 하위 프로세스에서 stdin을 / dev / tty로 다시여십시오. 이는 xargs가 대화식 응용 프로그램을 실행하도록하려는 경우에 유용합니다.

따라서 OSX에서 다음 명령을 사용할 수 있습니다.

find . -name "php.ini" | xargs -o vim

GNU 버전에는 직접 스위치가 없지만이 명령은 작동합니다. ( dummy문자열 을 포함시켜야합니다 . 그렇지 않으면 첫 번째 파일이 삭제됩니다.)

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy

위의 솔루션은 SuperUser의 Jaime McGuigan입니다 . 이 오류에 대해 사이트를 검색하는 향후 방문자를 위해 여기에 추가하십시오.


3
-o 팁에 감사합니다. 나는 xargs를 몇 년 동안 사용해 왔으며 그것을 알아 차리지 못했습니다 ... ... 시스템의 맨 페이지를 확인했습니다 .GNU xargs 기능이 아니기 때문입니다. 매뉴얼 페이지는 xargs sh -c 'emacs "$@" < /dev/tty' emacs보다 유연하고 이식 가능한 대안이라고 주장합니다 (GNU가 기능보다 이식성을 선호하는 것은 재미있는 일이지만).
cas

2

GNU findutils및 프로세스 대체 (ksh, zsh, bash)를 지원하는 쉘을 사용하여 다음을 수행 할 수 있습니다.

xargs -r0a <(locate -0 php.ini) vi

아이디어는 -a filenamestdin 이 아닌 파일 목록을 전달하는 것입니다. 를 사용 -0하면 파일 이름에 포함 할 수있는 문자 나 문자가 무엇이든 관계없이 작동합니다.

를 사용 zsh하면 다음을 수행 할 수 있습니다.

vi ${(0)"$(locate -0 php.ini)"}

(여기서 0NUL에서 분할 할 매개 변수 확장 플래그).

그러나 파일이 없으면 인수와 달리 xargs -r여전히 vi인수없이 실행 됩니다.


0

동일한 편집기에서 여러 php.ini를 편집 하시겠습니까?

시험: vim -o $(locate php.ini)


0

이 오류는 vim이 호출되고 터미널 대신 이전 파이프 라인의 출력에 연결되고 NUL과 같은 예기치 않은 다른 입력을 수신 할 때 발생합니다. 당신이 실행할 때와 동일한 상황이 발생합니다 vim < /dev/null, 그래서 reset이 경우 명령을 할 수 있습니다. 이것은 수퍼 유저의 grawity에 의해 잘 설명되어 있습니다 .

Unix / OSX에서는 다음 과 같은 매개 변수 xargs와 함께 사용할 수 있습니다 -o.

locate php.ini | xargs -o vim

-o명령을 실행하기 전에 하위 프로세스에서 stdin을 / dev / tty로 다시여십시오. 이는 xargs가 대화식 응용 프로그램을 실행하도록하려는 경우에 유용합니다.

Linux에서는 다음 해결 방법을 시도하십시오.

locate php.ini | xargs -J% sh -c 'vim < /dev/tty $@'

또는 다음과 같이 tty 할당을 강제 parallel로 수행 xargs하는 대신 GNU 를 사용하십시오 .

locate php.ini | parallel -X --tty vi

참고 : parallelUnix / OSX에서는 매개 변수가 다르고 tty를 지원하지 않으므로 작동하지 않습니다.

잘 (등 다른 많은 인기 명령은 의사 청각 장애 할당을 제공 -t에서 ssh), 그래서 도움이 있는지 확인합니다.

또는 find편집 할 파일 이름을 전달 하는 데 사용 하므로 xargs, 필요하지는 않습니다 -exec. 예를 들면 다음과 같습니다.

find /etc -name php.ini -exec vim {} +

0

@Patrick의 IFS핵은 bashand 같은 벙어리 껍질에만 필요합니다 zsh. fish 기본적으로 문자열을 줄 바꿈으로 나눕니다.

$ vim (locate php.ini)

그리고 우리 중 한 사람이 실제로 그 이름에 줄 바꿈이있는 파일을 가지고 있다면 하나님은 우리 모두를 도와 주 십니다. 리눅스를 사용한지 17 년이 지난 지금도 한 번도 보지 못했습니다. 나는 스크립트 파일에 줄 바꿈이있는 파일 이름을 지원하는 것을 귀찮게하고 싶지만, 그와 같은 스크립트는 vim을 대화 형으로 실행하지 않을 것입니다.


zsh기본적으로 SPC, TAB, NL 및 NUL에서 분할됩니다. 비교하지 않는 것은 bash결과에서 globbing을 수행하므로 파일 이름의 와일드 카드 문자는 문제가되지 않습니다. 에서 zsh, IFS=$'\0'; vi $(locate -0 php.ini)또는 vi ${(0)"$(locate -0 php.ini)"}명시 적 분할 연산자에 대한 답변 에 표시된 것처럼 수행 합니다. 또한 tcshvi "`locate php.ini`"
Stéphane Chazelas

아, 쓰레기 OK 이것은 작동 $ f='not there'<ret>$ ls $f<ret>하지만 이것이 작동하지 않습니다 : ls echo not there. 확인이 조금 업데이트해야 할 것 같습니다.
enigmaticPhysicist

네, 할 때 zsh는 옳은 일을하지 않습니다 ls "$(echo test; echo other test)". 물고기 만이 옳은 일을합니다.
enigmaticPhysicist

따옴표없이 똑같은 것을 의미한다고 가정하면, "올바른"것이 아니며, 줄로 나뉘어져 있으며, 단지 다른 선택입니다. zsh는 기본적으로 단어를 다른 모든 쉘과 같이 분할하며 $IFS명시 적 연산자 ( f0매개 변수 확장 플래그) 를 통해 또는 행을 통해 줄 또는 NUL에서 분할하도록 지시 할 수 있습니다 . 임의의 파일 이름, 단어로 나누거나 줄로 나누는 것도 똑같이 잘못 되면 NUL로 나누거나 인코딩 fish할 수없는 일부 구문 분석이 필요합니다. 에서 zsh, IFS=$'\0'; ls -ld -- $(printf '%s\0' "$file1" "$file2")또는ls -ld -- ${(0)"$(printf '%s\0' "$file1" "$file2")"}
Stéphane Chazelas

Meh. 개행으로 나누는 것으로 충분합니다. 대답에서 알 수 있듯이 파일 이름의 줄 바꿈은 극히 드 rare니다. 나는 그것이 17 년 안에 일어나는 것을 문자 그대로 본 적이 없다. 그리고 개행은 nuls보다 편리한 구분 기호입니다.
enigmaticPhysicist

0

빠른 방법은 당신이 SPC, TAB, NL, 포함 된 파일 경로 전혀 보장 할 수있는 가정, 그것을 할 *, ?, [(또한 자하는 것은 \{...}일부 껍질에) 백 틱 사용하는 것입니다 (일명 무덤 악센트) 이전에 명령을 실행 다른 명령이 실행 중입니다.

예 :

vi `find / -type f -name 'php.ini'`

백틱에 포함 된 명령이 먼저 실행됩니다. 그런 다음 포함 된 명령의 출력은 백틱 이전에 언급 된 명령에 의해 실행됩니다.

예를 들어 위의 행에서 find / -type f -name 'php.ini'명령은 먼저 vi실행되고 출력을 보낸 다음 해당 출력에 적용된 split + glob의 결과에 따라 실행됩니다.


3
작은 따옴표에는 백틱이 너무 쉽게 혼동됩니다. 사용하는 $(find ...)대신.
cas

1
이것을 추측하면 파일 이름의 공백 및 / 또는 줄 바꿈도 중단됩니까?
cwd

bash 스크립팅에서 쉘 명령을 실행하는 방법입니다. 스크립트의 공백이나 줄 바꿈 또는 한 줄에서 사용할 때 줄 바꿈이 없었습니다. 그러나이 vi방법 을 사용하여 여러 파일을 열려고 시도한 적이 없습니다 . vi출력을 읽고 실행하는 방법에 따라 줄 바꿈이나 공백으로 인해 깨질 수 있습니다.
tacotuesday
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.