
답변1
나는 이것을 처음 시도해 볼 것이다. 다른 사람들도 개선되기를 바랍니다.
스크립트를 실행하기 전에 쉘은 파일에 대한 파일 설명자를 엽니다. 일반적으로 fd 255에 할당됩니다. 어쨌든 open 이 있으면 찾을 수 있습니다 fd
. lsof
그래서 우리는 lsof -p $$
가장 높은 파일 설명자의 파일 이름을 사용하고 얻습니다. lsof
모든 UNIX 버전에 적용되는 것은 아닙니다. BSD 위키에는 동등한 것이 있다고 나와 있습니다 fstat
. Darwin(Mac OS)에 있는 것 같습니다. `-F로
예시 스크립트:
#!/bin/sh
this_script_path=`lsof -p $$ | awk '/\/'${0##*/}'$/' | cut -c 55-`
분명히 클리핑은 lsof의 특정 형식에 크게 의존합니다. 버전 2에서는 이 문제를 완화할 수 있습니다. 참고: 내 버전에서는 lsof
인쇄할 수 없는 문자를 변환하여 경로 이름의 탭 문자도 \t
.
버전 2. 못생긴 Perl 코드에 대해 미리 죄송합니다. 이번에는 -F
옵션을 사용하여 출력을 제어하겠습니다. 우리는 -F fn
다음과 같은 결과를 얻게 될 것입니다:
p3834
fcwd
n/home/joe/test
frtd
n/
ftxt
n/bin/bash
fmem
n/lib64/ld-2.12.so
fmem
n/lib64/libdl-2.12.so
fmem
n/lib64/libc-2.12.so
fmem
n/lib64/libtinfo.so.5.7
fmem
n/usr/lib/locale/locale-archive
fmem
n/usr/lib64/gconv/gconv-modules.cache
f0
n/dev/pts/1
f1
n/dev/pts/1
f2
n/dev/pts/1
f255
n/home/joe/test/t.sh
우리는 가장 높은 파일 설명자(255라고 믿을 수 없다고 가정합니다)가 스크립트 이름이 되도록 이 혼란스러운 부분을 변환해야 합니다. (이것도 dash
적용되는 것 같습니다.)
this_script_path=`lsof -p $$ -F fn |
perl -lane '
$fd=$1,next if /^f(\d+)/;
$p{$fd}=$1 if $fd and /^n(.*)/;
$fd="";
}END {
@x=sort {$a<=>$b} keys %p;
print $p{$x[-1]};
}{'`
Perl 스크립트는 보기 흉하다는 점에 동의합니다. 이것은 한 줄짜리이며 명확성을 위해 분류했습니다. 줄이 로 시작하면 파일 설명자의 번호를 캡처합니다. f
유효한 파일 설명자와 유효한 파일 이름이 있으면 파일 이름을 해시로 캡처합니다. 만일을 대비하여 이러한 조건 중 어느 것도 충족되지 않으면 을 취소합니다 $fd
. 모든 행이 처리된 후 해시(파일 설명자)의 키를 숫자로 정렬하고 결과를 배열에 저장한 다음 배열의 마지막 요소(가장 큰 값)로 색인이 지정된 x
파일 이름 hash의 내용을 출력합니다 .p
x
유일한 질문은 lsof가 모든 시스템에 설치되는지 여부와 이 출력 형식이 얼마나 안정적인지입니다.
답변2
도움이 될 수 있는 몇 가지 경험적 방법이 있지만 완전히 신뢰할 수 있는 방법은 없습니다.
Otheus는 파일 설명자를 사용하는 방법을 보여줍니다.. 이는 대부분의 경우에 작동하는 좋은 경험적 방법입니다. 그러나 실패하고 실패를 감지할 수 없는 극단적인 경우가 있습니다.
예: 다음 스크립트를 사용하세요.
#!/bin/sh
set
lsof -p$$ | sed 's/[0-9][0-9]*//'
이 스크립트의 복사본 두 개를 만듭니다. 하나는 이름이 지정 foo
되고 다른 하나는 bar
. 이제 조금 강조해 보겠습니다.
$ env -i PATH=/bin:/usr/bin perl -MPOSIX -e 'dup2(4, 11) or die $!; exec "dash", "foo", "bar"' 3<foo 4<bar </dev/null >foo.out
$ env -i PATH=/bin:/usr/bin perl -MPOSIX -e 'dup2(3, 10) or die $!; exec "dash", "bar", "foo"' 3<foo 4<bar </dev/null >bar.out
$ diff foo.out bar.out
17c17 < dash gils 1w reg 0,24 99 10130024 /tmp/202954/foo.out ---
대시 자일스 1w REG 0,24 99 10130022 /tmp/202954/bar.out
여기서 유일한 차이점은 출력을 기록하는 파일입니다.
이 경험적 방법이 실패하는 또 다른 경우는 쉘이 표준 입력에서 호출되거나 -c
.
또 다른 접근 방식은 쉘의 명령줄을 구문 분석하는 것입니다. Linux에서는 /proc
인수가 null로 구분되므로 휴대용 셸 도구로 구문 분석하기 어렵지만(최근 GNU 도구를 사용하면 더 쉬워짐) 수행할 수 있습니다. 이식 가능한 매개변수에 액세스하려면 호출해야 하며 ps
명시적인 출력 형식은 없습니다. ps -o args
매개변수는 공백으로 연결되며 잘릴 수 있습니다.
Linux에서도 여기서 발생하는 문제는 스크립트가 알지 못하는 옵션으로 셸이 호출될 수 있고 해당 옵션 중 하나가 인수를 취할 수 있다는 것입니다. 예를 들어, 이름이 붙은 스크립트 1
와 이름이 다른 스크립트가 있다고 가정해 보겠습니다 2
.
mksh -T 1 2
그러면 mksh가 호출되고 /dev/tty1
스크립트가 실행됩니다 2
.
zsh -T 1 2
옵션을 사용하여 zsh를 호출하고 cprecedences
인수를 사용하여 스크립트를 실행합니다.1
2
각 쉘을 구별하려면 각 쉘을 알아야 합니다. 이 접근 방식을 사용하면 극단적인 경우를 감지할 수 있습니다. 비표준 옵션이 보이면 그냥 종료하세요.