macOS에서 df --output이 unrecognized option 오류를 낼 때: 오류가 디스크 여유 검사를 통과시키는 자리와 -P 가 맥과 GNU 에서 다른 단위를 내는 이유를 직접 시험한 결과When df --output fails with unrecognized option on macOS: where the error lets a free-space check pass, and why -P prints different units on a Mac and on GNU, tested directly
리눅스식 df --output=avail 을 macOS 에서 돌려 오류를 만났거나 df 로 뽑은 남은 용량이 이상한 독자가, 원인을 가려내고 맥과 리눅스에서 같은 값을 내는 방법과 실패를 걸러 내는 방법을 고르게 돕는다.
이 맥(26.6.2)의 df 는 --output·--block-size·--total 등 GNU 긴 옵션은 unrecognized option, -B 는 invalid option 과 종료 코드 64로 거부하고, 오류를 버린 값은 빈 문자열이라 [ "" -lt N ] 검사가 '충분하다'로 통과한다. 맥 df 의 기본 단위는 512바이트 블록이라 4열을 KiB 로 읽으면 두 배가 되고, -P 도 맥에서는 512, GNU 에서는 1024 블록이므로 df -Pk 경로 | awk 'NR==2{print $4}' 에 숫자 검증을 붙인 함수가 gdf·python 값과 일치했다.
스크립트에서 df --output 이나 df 4열을 바로 쓰는 곳을 찾아 아래 함수로 바꾸고, 없는 경로를 줘서 중단되는지 한 번 돌려 보라.
한 줄 요약: 이 맥(26.6.2)의 df 는 –output 을 종료 코드 64로 거부하고 오류를 버린
-lt여유 검사는 ’충분하다’로 통과하므로, df -Pk 와 awk 에 숫자 검증을 붙인 함수를 쓴다.
리눅스에서 df --output=avail / 로 남은 용량을 뽑던 스크립트를 맥 터미널에 붙였더니 아래처럼 실패한다. 이 글은 그 오류가 왜 나는지, 오류를 지나친 디스크 여유 검사에서 무슨 일이 생기는지, 맥과 리눅스에서 같은 값을 얻으려면 무엇을 쓰면 되는지를 이 맥에서 직접 돌려 보인다.
df: unrecognized option `--output=avail'
확인한 환경은 macOS 26.6.2 arm64 의 /bin/df(file_cmds-479), 비교용으로 Homebrew 의 GNU coreutils 9.11 에 든 gdf, bash 3.2.57 이다. 시험 스크립트는 LC_ALL=C 로 두 번씩 돌렸고, 남은 용량과 Used 는 두 번 실행 사이에 약 1.2 MiB(1,188 KiB) 바뀌었으므로 값 대신 같은 시점의 비율이나 차이로 비교했고, 본문의 숫자는 첫 실행 값이다. 같은 오류 문구가 적힌 공개 기록은 찾지 못했다. 대신 맥의 df 가 inode 열까지 기본으로 찍어 열을 줄이는 법을 묻는 질문(Ask Different, 2016)과 / 와 /System/Volumes/Data 의 사용량이 다르다는 질문(2019)이 공개돼 있다.
용어 몇 개. df 는 파일 시스템(볼륨)의 크기·사용량·남은 용량을 보여 주는 명령이다. 블록은 용량을 세는 단위로, 512바이트일 수도 1024바이트일 수도 있다. 종료 코드는 명령이 끝나며 남기는 숫자로 0이 정상이다. GNU 는 많은 리눅스 배포판이 쓰는 명령 모음이고, 맥의 명령은 BSD 계열이라 옵션이 다르다. KiB 는 1024바이트, MiB 는 1024 KiB, GiB 는 1024 MiB 다. inode 는 파일 하나의 정보를 담는 항목이고 df 의 iused·ifree 열은 그 사용 개수와 남은 개수다. PIPESTATUS 는 bash 가 파이프의 명령별 종료 코드를 담는 배열이고(이 글에서 zsh 의 같은 변수는 시험하지 않았다), set -e 는 명령이 실패하면 스크립트를 멈추는 설정, set -o pipefail 은 파이프 중간 명령의 실패도 파이프 전체의 실패로 치는 설정이다. os.statvfs 는 파이썬이 운영체제에 남은 용량을 직접 묻는 함수로, 값을 맞춰 보는 기준으로만 썼다.
맥의 df 가 거부하는 옵션과 받아 주는 옵션
--output, --block-size, --total, --sync, --local, --portability, --version, --help 는 모두 unrecognized option 과 종료 코드 64였고 표준 출력은 비어 있었다. -B 1K 도 invalid option -- B 와 64였다. 반대로 -P, -k, -l, -H, --si 는 종료 코드 0으로 동작했다. 같은 옵션을 gdf 9.11 에 주면 --output=avail, -B 1K, --total, --si, --sync, -P 모두 종료 코드 0이었다. GNU 설명서는 --output[=field_list] 를 열 목록을 골라 출력하는 옵션으로 적고 avail 은 사용 가능한 블록 수라고 적는다. 맥의 df 에는 이 기능이 없다.
오류를 숨기면 검사가 통과한다
여유 용량을 확인하는 흔한 줄을 시험했다.
avail=$(df --output=avail / 2>/dev/null | tail -1) # avail 은 빈 문자열
if [ "$avail" -lt 1000000 ]; then echo "여유 부족, 중단"; else echo "충분하다고 보고 진행"; fi
파이프의 종료 코드($?)는 0이었지만 PIPESTATUS 는 64 0 이었다. [ "" -lt 1000000 ] 은 integer expression expected 를 내며 실패해 else 쪽, 곧 “충분하다고 보고 진행”이 나왔다. 반대로 -ge 로 쓴 검사는 “부족하다고 보고 중단”이 나왔다. 같은 오류인데 오류 문구는 한 줄 나올 뿐이고, 검사를 어느 방향으로 쓰느냐에 따라 흐름이 그냥 통과하거나 괜히 멈춘다. 산술 확장 $((avail / 1024)) 는 빈 값을 0으로 읽어 0이 됐다. set -e 아래의 같은 대입은 멈추지 않고 v=[] 로 통과했고, set -o pipefail 을 같이 켜야 종료 코드 64로 멈췄다.
오류 없이 어긋나는 것: 단위와 열
옵션이 통과해도 값이 어긋나는 자리가 있다. 같은 / 에서 4열(Available)을 맥 df -k 의 4열로 나눈 비율을 쟀다.
| 명령 | 헤더의 단위 | 4열 비율 |
|---|---|---|
맥 df / |
512-blocks | 2.00 |
맥 df -k / |
1024-blocks | 1.00 |
맥 df -P / |
512-blocks | 2.00 |
맥 df -Pk / |
1024-blocks | 1.00 |
gdf / |
1K-blocks | 1.00 |
gdf -P / |
1024-blocks | 1.00 |
맥의 기본 단위는 512바이트 블록이고 -P 도 512바이트 블록이다. GNU 의 기본은 1K 블록이고 -P 는 1024 블록이다. GNU 설명서는 -P 의 단위가 POSIXLY_CORRECT 가 있으면 512, 없으면 1024 라고 적고, 이 시험에서도 POSIXLY_CORRECT=1 이면 gdf -P 가 512-blocks 였다. 그래서 df -P / | awk 'NR==2{print $4}' 는 두 시스템에서 값이 두 배 다르다. 맥 df -k / 4열의 두 배를 맥 df / 의 4열(512블록 값)로 삼아 KiB 로 읽고 GiB 로 바꾸면 281.6 GiB, 실제 값은 140.8 GiB 였다. BLOCKSIZE 환경 변수를 1m 으로 두면 맥 df 의 헤더가 1M-blocks 가 되지만 df -P 는 512, df -k 는 1024 로 그대로였다. -k 를 함께 쓴 df -Pk 는 BLOCKSIZE 를 1024·1m·1g 로 줘도 맥에서 1024-blocks 였고(맥 man 은 -k 가 -P 를 이긴다고 적는다), gdf -Pk 도 BLOCKSIZE=1m, DF_BLOCK_SIZE=1m, POSIXLY_CORRECT=1 을 줘도 1024-blocks 였다(두 경우 모두 헤더의 단위 표기만 쟀다). 그래서 단위를 명시하는 df -Pk 는 이 시험 범위에서 두 시스템이 같은 1024 블록이다.
열 수도 다르다. 맥 df -k / 는 inode 열이 기본으로 붙어 헤더를 공백으로 나눈 칸이 10개(Mounted on 이 둘로 나뉜다)이고, df -Pk / 와 gdf -k / 는 7개다. 4열은 어느 쪽에서나 Available 이지만, 마운트 위치를 $6 같은 번호로 읽던 스크립트는 맥에서 -P 없이 돌리면 inode 열(iused)을 읽게 된다.
/ 의 사용량도 읽는 법이 필요하다. 이 맥에서 df -Pk / 는 사용 12,341,740 KiB(약 11.8 GiB), Capacity 8% 였지만 /System/Volumes/Data 와 $HOME 은 사용 310,558,584 KiB(약 296 GiB), 68% 였다. 두 번째 실행의 Data 사용량은 310,557,396 KiB 였다. 두 볼륨의 Available 은 차이가 0 KiB 로 같았다. mount 로 보면 / 는 disk3s1s1 에 apfs, sealed, local, read-only 로 마운트돼 있고 touch /파일 은 Read-only file system 으로 실패했으며, 사용자 파일이 있는 /System/Volumes/Data 는 disk3s5 다. 이 글은 sealed 와 read-only 를 시스템 볼륨이 변경할 수 없게 봉인돼 있다는 표시로 읽었다. 그래서 / 의 Used 는 읽기 전용 시스템 볼륨의 크기이고, Available 이 같은 것으로 보아 같은 저장 공간을 쓰는 것으로 보이지만(컨테이너 구성은 확인하지 않았다) 얼마나 찼는지를 보려면 / 가 아니라 실제 파일이 있는 경로를 줘야 한다.
두 시스템에서 같은 값을 내는 함수
아래 함수는 경로 하나를 받아 그 경로가 있는 볼륨의 남은 KiB 를 한 줄 출력하고, 실패하면 아무것도 쓰지 않고 1을 돌려준다.
df_avail_kb() { # 사용: df_avail_kb 경로 -> 남은 KiB. 실패하면 출력 없이 1, 인자 오류는 2
local v
[ $# -eq 1 ] || return 2
v=$(df -Pk -- "$1" 2>/dev/null | awk 'NR==2 { print $4 }') || return 1
case $v in ''|*[!0-9]*) return 1 ;; esac
printf '%s\n' "$v"
}
av=$(df_avail_kb "$HOME") || { echo "남은 용량을 못 쟀다" >&2; exit 1; }
[ "$av" -ge 1048576 ] || { echo "1 GiB 미만" >&2; exit 1; }
/, $HOME, 임시 폴더에서 함수 값은 gdf --output=avail -k 와 python3 os.statvfs 값과 차이가 0 KiB 였다. 공백이 든 폴더, 파일 경로, /System/Volumes/Data 모두 종료 코드 0으로 숫자를 냈고, 없는 경로는 df: /no/such/path: No such file or directory(종료 코드 1)를 버리고 빈 값과 종료 코드 1을 돌려줬다. 인자 없이 부르면 종료 코드 2였다. 시험 스크립트에서는 이 함수를 쓴 검사를 같은 꼴로 만들어 99999999999 KiB 를 요구하면 “부족”(종료 코드 1), 없는 경로면 “측정 실패”(종료 코드 2)로 나눠 멈추게 했고(위 호출부는 둘 다 1 로 멈춘다), set -euo pipefail 아래의 없는 경로 대입은 종료 코드 1로 멈췄다. 같은 함수를 zsh 에 넘겨도 / 에서 숫자, 없는 경로에서 1이었고, / 를 20번 재는 동안 실패는 0번이었다. 경로를 두 개 이상 주면 df 가 줄을 여러 개 내므로 이 함수는 한 경로만 받게 했다(tail -1 로 잡으면 마지막 경로 줄이 된다).
Homebrew 의 coreutils 를 깔아 gdf --output=avail 을 쓰는 방법도 있지만 그 도구가 있는 맥에서만 된다.
시험하지 못한 것
리눅스에서 도는 GNU df 는 쓰지 못했고 이 맥의 gdf 9.11 이 대신했다. zsh(함수 호출 두 줄 말고는), 다른 macOS 버전, 네트워크 마운트처럼 장치 이름이 긴 볼륨, 외부 디스크와 디스크 이미지, 장치 이름에 공백이 있어 df -Pk 의 4열이 밀릴 수 있는 줄(공개 질문 기록의 map auto_home 같은 항목)은 확인하지 못했다. 공개 질문 두 건은 증상과 맥락을 확인하는 근거로만 썼다.
세 줄 요약
- 이 맥(26.6.2)의 df 는 –output·–block-size·–total 을 unrecognized option, -B 를 invalid option 으로 종료 코드 64로 거부하고 -P·-k·-H·–si 는 받아 준다.
- 오류를 버린 값은 빈 문자열이라 [ “” -lt N ] 검사가 ’충분하다’로 통과하고, 맥 df 는 기본이 512바이트 블록이며 -P 도 맥은 512, GNU 는 1024 블록이다.
- df -Pk – 경로 | awk ‘NR==2{print $4}’ 에 숫자 검증을 붙인 함수가 gdf·statvfs 값과 일치했고, 없는 경로에서는 출력 없이 1을 돌려줬다.
To help a reader who ran Linux-style df --output=avail on macOS and hit an error, or whose free space pulled from df looks wrong, find the cause and choose a way to get the same value on a Mac and on Linux and to filter out failures.
The df on this Mac (26.6.2) rejects GNU long options such as --output, --block-size and --total with unrecognized option, and -B with invalid option, all with exit code 64, and a value whose error was discarded is an empty string, so a [ "" -lt N ] check passes as 'enough'. The default unit of the Mac df is 512-byte blocks, so reading column 4 as KiB doubles it, and -P is 512 on the Mac but 1024 on GNU, so a function that adds a numeric check to df -Pk path | awk 'NR==2{print $4}' matched the gdf and python values.
Find where your scripts use df --output or df column 4 directly, replace them with the function below, and run it once with a path that does not exist to see that it stops.
Contents
One-line summary: The df on this Mac (26.6.2) rejects –output with exit code 64, and a
-ltfree-space check that discards the error passes as ‘enough’, so use a function that adds a numeric check to df -Pk and awk.
I pasted a script that pulled free space with df --output=avail / on Linux into a Mac terminal, and it failed as below. This article shows, by running it directly on this Mac, why that error happens, what happens to a free-space check that walks past the error, and what to use to get the same value on a Mac and on Linux.
df: unrecognized option `--output=avail'
The environment I checked was /bin/df (file_cmds-479) on macOS 26.6.2 arm64, gdf from Homebrew’s GNU coreutils 9.11 for comparison, and bash 3.2.57. I ran the test scripts twice each with LC_ALL=C. Free space and Used changed by about 1.2 MiB (1,188 KiB) between two runs, so I compared ratios or differences taken at the same moment instead of the values, and the numbers in this article are from the first run. I did not find a public record with the same error text. What is public instead is a question about how to cut the inode columns that the Mac df prints by default (Ask Different, 2016) and a question about why the usage of / and /System/Volumes/Data differs (2019).
A few terms. df is a command that shows the size, usage and free space of a file system (volume). A block is the unit for counting space, and it can be 512 bytes or 1024 bytes. The exit code is the number a command leaves when it finishes, and 0 means normal. GNU is the command collection many Linux distributions use, and the Mac commands are BSD-family, so their options differ. KiB is 1024 bytes, a MiB is 1024 KiB, and a GiB is 1024 MiB. An inode is an entry that holds the information of one file, and the iused and ifree columns of df are the number of those in use and the number left. PIPESTATUS is an array in which bash keeps the exit code of each command in a pipe (I did not test the equivalent variable in zsh for this article), set -e is a setting that stops the script when a command fails, and set -o pipefail is a setting that counts a failure of a middle command in a pipe as a failure of the whole pipe. os.statvfs is a Python function that asks the operating system for free space directly, and I used it only as a reference to check values against.
Options the Mac df rejects and options it accepts
--output, --block-size, --total, --sync, --local, --portability, --version and --help all gave unrecognized option with exit code 64, and standard output was empty. -B 1K also gave invalid option -- B and 64. Conversely, -P, -k, -l, -H and --si worked with exit code 0. Giving the same options to gdf 9.11, --output=avail, -B 1K, --total, --si, --sync and -P all exited with 0. The GNU manual describes --output[=field_list] as an option that prints a chosen list of columns, and says avail is the number of available blocks. The Mac df does not have this feature.
Hiding the error lets the check pass
I tested a common line that checks free space.
avail=$(df --output=avail / 2>/dev/null | tail -1) # avail is an empty string
if [ "$avail" -lt 1000000 ]; then echo "not enough space, stop"; else echo "assume enough and proceed"; fi
The exit code of the pipe ($?) was 0, but PIPESTATUS was 64 0. [ "" -lt 1000000 ] printed integer expression expected and failed, so the else branch, “assume enough and proceed”, was printed. A check written with -ge instead printed “assume not enough and stop”. With the same error, the error message is just one line, and the flow either passes straight through or stops for no reason, depending on which direction the check is written. The arithmetic expansion $((avail / 1024)) read the empty value as 0 and gave 0. The same assignment under set -e did not stop and passed with v=[], and it stopped with exit code 64 only when set -o pipefail was turned on as well.
What differs without any error: units and columns
Even when an option passes, there are places where the value goes off. On the same /, I measured column 4 (Available) divided by column 4 of the Mac df -k.
| Command | Unit in the header | Ratio of column 4 |
|---|---|---|
Mac df / |
512-blocks | 2.00 |
Mac df -k / |
1024-blocks | 1.00 |
Mac df -P / |
512-blocks | 2.00 |
Mac df -Pk / |
1024-blocks | 1.00 |
gdf / |
1K-blocks | 1.00 |
gdf -P / |
1024-blocks | 1.00 |
The default unit of the Mac is 512-byte blocks, and -P is also 512-byte blocks. The GNU default is 1K blocks, and -P is 1024 blocks. The GNU manual says the unit of -P is 512 if POSIXLY_CORRECT is set and 1024 if not, and in this test too gdf -P gave 512-blocks with POSIXLY_CORRECT=1. So df -P / | awk 'NR==2{print $4}' gives values that differ by a factor of two on the two systems. Taking twice column 4 of the Mac df -k / as column 4 of the Mac df / (the 512-block value), reading it as KiB and converting to GiB gave 281.6 GiB, while the real value was 140.8 GiB. Setting the BLOCKSIZE environment variable to 1m makes the header of the Mac df say 1M-blocks, but df -P stayed at 512 and df -k at 1024. df -Pk, which also uses -k, gave 1024-blocks on the Mac with BLOCKSIZE set to 1024, 1m or 1g (the Mac man page says -k overrides -P), and gdf -Pk also gave 1024-blocks with BLOCKSIZE=1m, DF_BLOCK_SIZE=1m or POSIXLY_CORRECT=1 (in both cases I only measured the unit shown in the header). So df -Pk, which states the unit, is the same 1024 blocks on both systems within this test.
The number of columns differs too. The Mac df -k / gets the inode columns by default, so splitting its header on spaces gives 10 fields (Mounted on is split in two), while df -Pk / and gdf -k / give 7. Column 4 is Available on either side, but a script that read the mount point by a number such as $6 would read the inode column (iused) when run on a Mac without -P.
The usage of / also needs a way to read it. On this Mac, df -Pk / showed used 12,341,740 KiB (about 11.8 GiB) and Capacity 8%, but /System/Volumes/Data and $HOME showed used 310,558,584 KiB (about 296 GiB) and 68%. The Data usage in the second run was 310,557,396 KiB. The Available of the two volumes was the same, with a difference of 0 KiB. mount shows / mounted on disk3s1s1 as apfs, sealed, local, read-only, and touch /file failed with Read-only file system, while /System/Volumes/Data, which holds the user files, is disk3s5. I read sealed and read-only as a sign that the system volume is sealed against change. So the Used of / is the size of the read-only system volume. Because the Available is the same they appear to use the same storage (I did not check the container layout), but to see how full it is, you have to give the path where the real files are, not /.
A function that gives the same value on both systems
The function below takes one path, prints on one line the free KiB of the volume the path is on, and on failure writes nothing and returns 1.
df_avail_kb() { # usage: df_avail_kb path -> free KiB. On failure no output and 1, wrong arguments 2
local v
[ $# -eq 1 ] || return 2
v=$(df -Pk -- "$1" 2>/dev/null | awk 'NR==2 { print $4 }') || return 1
case $v in ''|*[!0-9]*) return 1 ;; esac
printf '%s\n' "$v"
}
av=$(df_avail_kb "$HOME") || { echo "could not measure free space" >&2; exit 1; }
[ "$av" -ge 1048576 ] || { echo "under 1 GiB" >&2; exit 1; }
On /, $HOME and a temporary folder, the function value differed from the gdf --output=avail -k and python3 os.statvfs values by 0 KiB. A folder with a space in the name, a file path and /System/Volumes/Data all printed a number with exit code 0, and a path that does not exist discarded df: /no/such/path: No such file or directory (exit code 1) and returned an empty value with exit code 1. Called with no argument, it gave exit code 2. In the test script I built a check using this function in the same form, and requiring 99999999999 KiB made it stop with “not enough” (exit code 1) and a path that does not exist made it stop with “measurement failed” (exit code 2) (the call site above stops with 1 in both cases), and under set -euo pipefail the assignment for a path that does not exist stopped with exit code 1. Passing the same function to zsh gave a number on / and 1 on a path that does not exist, and while measuring / 20 times there were 0 failures. If you give two or more paths, df prints several lines, so I made this function accept only one path (picking with tail -1 would take the last path’s line).
Installing Homebrew’s coreutils and using gdf --output=avail is also possible, but it works only on a Mac that has that tool.
What I could not test
I could not use the GNU df running on Linux, and the gdf 9.11 on this Mac stood in for it. I did not check zsh (beyond the two lines that call the function), other macOS versions, volumes with long device names such as network mounts, external disks and disk images, or lines where a space in the device name could shift column 4 of df -Pk (an entry like map auto_home in the public question record). I used the two public questions only as evidence for the symptoms and the context.
Three-line summary
- The df on this Mac (26.6.2) rejects –output, –block-size and –total with unrecognized option and -B with invalid option, all with exit code 64, and accepts -P, -k, -H and –si.
- A value whose error was discarded is an empty string, so a [ “” -lt N ] check passes as ‘enough’, and the Mac df defaults to 512-byte blocks, and -P is 512 on the Mac but 1024 blocks on GNU.
- A function that adds a numeric check to df -Pk – path | awk ‘NR==2{print $4}’ matched the gdf and statvfs values, and for a path that does not exist it returned 1 with no output.