내 파일이 어떤 장치에 있는지 확인하여 스크립트에서 사용할 수 있도록 하고 싶습니다. 나는 이것을 할 수 있다:
$ df .
Filesystem 512-blocks Used Available Capacity Mounted on
/dev/disk0s2 498438976 294369520 203557456 60% /
하지만 이 출력이 너무 투박해 보입니다. 두 번째 줄의 첫 번째 "단어"를 얻기 위해 구문 분석하는 것보다 더 좋은 방법이 있습니까?
나에게 정말로 필요한 것은 다음 명령으로 파이프할 수 있도록 하는 것과 같은 것입니다.
$ somecommand .
/dev/disk0s2
"df" 출력에서 문자열 해킹을 사용하지 않고 이를 달성하려면 어떻게 해야 합니까?
답변1
셸만 사용하여 이 작업을 수행할 수 있습니다( bash
, dash
, ksh
, 에 적용 zsh
).
df . | (read a; read a b; echo "$a")
또는 출력이 필요하지 않고(결과는 $a에 저장됨) 쉘이 프로세스 대체를 지원하는 경우(예: bash
, zsh
):
{ read; read a b;}< <(df .)
다음은 다른 솔루션의 속도와의 몇 가지 비교입니다.
# pure shell solution 1
bash-4.2$ time for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null
1.899
(dash) $ time -f '%e' dash -c 'for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null'
1.05
(ksh) $ time for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null
0m1.16s real 0m0.02s user 0m0.12s system
(zsh) manatwork% time (for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null)
1.51s
# pure shell solution 2
bash-4.2$ time for i in $(seq 500); do { read; read a b;}< <(df .); done
1.192
(zsh) manatwork% time (for i in $(seq 500); do { read; read a b;}< <(df .); done)
3.51s
# other solutions
bash-4.2$ time for i in $(seq 500); do df . | tail -1 | cut -f 1 -d " "; done > /dev/null
1.405
bash-4.2$ time for i in $(seq 500); do df . | sed '2!d' | awk '{print $1}'; done > /dev/null
5.407
bash-4.2$ time for i in $(seq 500); do df . | sed -n '2{s/ .*$//;p}'; done > /dev/null
1.767
bash-4.2$ time for i in $(seq 500); do df . | sed '2!d' | awk '{print $1}'; done > /dev/null
3.334
bash-4.2$ time for i in $(seq 500); do df . | gawk 'NR==2{print $1}'; done > /dev/null
3.013
bash-4.2$ time for i in $(seq 500); do df . | mawk 'NR==2{print $1}'; done > /dev/null
1.747
bash-4.2$ time for i in $(seq 500); do df . | perl -nae 'print$F[0]if$.==2'; done > /dev/null
2.752
( stat
여기에서는 작동하지 않으므로 솔루션과 비교되지 않습니다.)
답변2
이것은 일반적으로 그렇습니다UNIX에서의 방법간단한 프로그램의 기능을 비트별로 연결합니다. 따라서 df
일부 필터를 통해 출력을 전달하는 것에 대해 걱정하지 마십시오 .
df /path/to/file | sed -n '2{s/ .*$//;p}'
-n
자동으로 인쇄 줄을 억제하고, 2{}
두 번째 줄에 포함된 명령을 실행하고, s/ .*$//
첫 번째 공백의 모든 내용을 버리고 p
나머지를 인쇄합니다. 더 긴 입력을 구문 분석하고 두 번째(또는 n번째) 줄만 필요한 상황에서 q
추가하면 p
작업 속도가 빨라질 수도 있습니다 .
답변3
sed
다음과 같은 간단한 한 줄을 사용할 awk
수 있습니다 .
df . | sed '2!d' | awk '{print $1}'
에서 sed
지정하는 것은 2d
두 번째 행을 삭제하는 것을 의미합니다 . !
다른 모든 줄을 삭제하고 두 번째 줄을 인쇄하도록 부정을 추가합니다 . 그런 다음 명령은 awk
값의 첫 번째 열을 표시합니다.
산출:
/dev/disk0s2
답변4
Linux를 사용하는 경우 findmnt
( util-linux
패키지의 일부)를 사용할 수 있습니다."스트링 해킹에 의지할 필요가 없습니다":
findmnt -no source -T /path/to/file
/dev/sda1
이 옵션을 사용할 때
-T, --대상길경로가 마운트 지점 파일이나 디렉터리가 아닌 경우
findmnt
마운트 지점을 얻기 위해 경로 요소를 역순으로 확인합니다. 다른 두 가지 옵션은 헤더 행을 억제 -n, --noheading
하고 나열할 열을 선택합니다.-o, --output
df
from에는 특정 필드만 인쇄하는 coreutils
유사한 옵션이 있습니다 . 예를 들면 다음과 같습니다.--output=
source
df --output=source /path/to/file
파일 시스템 /dev/sda1
하지만 제목을 삭제할 수 있는 옵션은 없습니다. 이것이 문제라면 최소한의 조치를 취해야 합니다.문자열 해커예를 들어 파이프로sed 1d