macOS에서 ps aux --sort=-%mem이 illegal option 오류를 낼 때: 메모리·CPU 순으로 프로세스를 줄 세우는 맥의 방법을 직접 시험한 결과When ps aux --sort=-%mem fails with an illegal option error on macOS: how to sort processes by memory or CPU with the Mac's own ps, tested directly
리눅스식 ps --sort 줄을 맥에서 돌려 오류를 만났거나, 오류를 숨긴 스크립트가 빈 값을 받은 독자가 맥 ps 만으로 메모리·CPU 순 목록을 얻는 방법을 고르게 돕는다.
이 맥(26.6.2)의 ps 는 GNU 긴 옵션(시험한 --sort·--forest·--no-headers·--pid·--version·--help)을 모두 종료 코드 1로 거부한다. 대신 ps aux -m 이 메모리 내림차순, ps -er -o pid,pcpu,comm 이 CPU 내림차순이고, 알려진 크기의 프로세스 네 개에서는 sort 파이프와 같은 순서였으며 전체 프로세스 646줄에서도 내림차순이었다. 헤더를 없애려면 -o pid= 처럼 등호를 붙이고, etimes 는 etime 을 awk 로 초로 바꾼다.
스크립트의 ps --sort 줄을 ps aux -m 이나 ps -em -o pid,pmem,comm 으로 바꾸고, 오류를 2>/dev/null 로 버리는 곳이 없는지와 pipefail 이 켜져 있는지 확인하라.
목차
한 줄 요약: 맥의 ps 는 –sort 를 종료 코드 1로 거부하지만, ps aux -m 이 메모리 내림차순, ps -er -o pid,pcpu,comm 이 CPU 내림차순이라 그 형태로 바꾸면 된다.
리눅스에서 메모리를 많이 쓰는 프로세스를 찾던 ps aux --sort=-%mem | head 를 맥 터미널에서 돌리면 목록 대신 오류와 usage 만 나온다. 이 글은 맥 ps 만으로 같은 줄 세우기를 하는 방법이 어디까지 믿을 만한지, 오류를 숨긴 스크립트가 왜 조용히 빈 값을 받는지, 같은 -m 이 리눅스에서는 다른 뜻인 점을 이 맥에서 직접 돌려 보인다.
/bin/ps: illegal option -- -
usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]]
확인한 환경은 macOS 26.6.2 arm64 의 /bin/ps, bash 3.2.57 이고 날짜는 2026-10-30 이다. 시험 스크립트 세 개를 두 번씩 돌렸고 두 번째 결과는 첫 번째와 같았다. 다른 것은 프로세스 메모리 숫자(48~160 KiB)뿐이었다. 전체 프로세스를 센 시험은 두 번 모두 646줄이었다. 비교 기준으로 쓸 GNU ps 는 이 맥에 없어서(procps 설치 없음) 리눅스 쪽 서술은 procps-ng 의 ps(1) 설명서(man7.org, 2025-04-23 판)를 읽은 것이고 직접 돌린 것이 아니다. 같은 방법을 공개 글도 안내한다. Apple Gazette 의 ps 명령 소개 글은 ps -er -o pid,pcpu,comm 이 CPU 순 정렬이고 메모리 순은 -r 대신 -m 을 쓰라고 적는다.
용어 몇 개. GNU 는 많은 리눅스 배포판이 쓰는 명령 모음이고, 맥의 명령은 BSD 계열이라 같은 이름이어도 옵션이 다르다. 종료 코드는 명령이 끝나며 남기는 숫자로 0이 정상이다. RSS 는 프로세스가 지금 실제 메모리에 올려 둔 크기(KiB)이고 %MEM 은 그것이 전체 메모리에서 차지하는 비율이다. pipefail 은 파이프 중간 명령이 실패해도 전체를 실패로 세는 셸 설정이다.
맥의 ps 가 거부하는 옵션과 받아 주는 옵션
옵션을 하나씩 붙여 종료 코드를 쟀다. 맥은 시험한 GNU 긴 옵션을 모두 같은 문장으로 거부했고 종료 코드는 1이었다. 오류 문장은 어느 옵션이 문제인지 알려 주지 않는다. ps --sort, ps --forest, ps --pid=1 세 줄의 첫 줄이 모두 똑같이 illegal option -- - 였다.
| 옵션 | 맥 /bin/ps |
|---|---|
--sort=-%mem, --sort=-pcpu, --sort=-rss |
1 (illegal option -- -) |
--forest, --no-headers, --pid 1, --version, --help |
1 (illegal option -- -) |
-o etimes, -o nlwp, -o thcount |
1 (keyword not found) |
-o %mem,%cpu, -o pcpu,pmem, -o rss,vsz,comm, -o args |
0 |
aux, -m, -r, -A -m |
0 |
마지막 두 줄이 이 글의 해결책이다. 맥 설명서(man ps)는 -m 을 “제어 터미널과 프로세스 번호의 조합 대신 메모리 사용량으로 정렬”, -r 을 “현재 CPU 사용량으로 정렬”이라고 적는다. 그런데 GNU ps 설명서는 같은 글자를 다르게 적는다. -m 은 “프로세스 뒤에 스레드를 보여 준다”(Show threads after processes)이고, BSD 식으로 대시 없이 쓰는 r 은 “실행 중인 프로세스만 고른다”(Restrict the selection to only running processes)이다. 그러니 맥식 ps aux -m 을 리눅스 서버에 그대로 가져가면 정렬이 되지 않고 스레드가 붙어 나오는 쪽일 수 있다. 이 부분은 설명서를 읽은 것이고 리눅스에서 돌려 보지는 못했다.
오류를 버리면 빈 값이 성공처럼 지나간다
오류 화면이 지저분해 2>/dev/null 을 붙이면 어떻게 되는지 쟀다. ps aux --sort=-%mem 2>/dev/null | head -3 는 아무것도 출력하지 않았다(결과 문자열 길이 0). 파이프 각 단계의 종료 상태를 모은 PIPESTATUS 는 1 0 이었고, pipefail 이 없으면 파이프 전체는 head 의 0으로 끝났다($? 가 0). pipefail 을 켜면 파이프 전체가 1이었다. 그러므로 “메모리 많이 쓰는 프로세스 이름” 을 변수에 담아 쓰던 스크립트를 맥으로 옮겼는데 변수가 비어 있다면 2>/dev/null 과 pipefail 부재부터 의심한다.
맥 ps 로 줄 세우는 방법과 믿을 수 있는 범위
메모리 크기를 아는 프로세스 네 개를 만들어 확인했다. 파이썬으로 30·60·120·240 MB 를 잡아 두고 40초 잠들게 한 프로세스들이다. 아래 세 방법이 네 프로세스를 모두 같은 순서(240, 120, 60, 30)로 줄 세웠다.
| 잡은 메모리 | %MEM |
RSS (KiB, 한 번의 실행) |
|---|---|---|
| 240 MB | 1.5 | 254048 |
| 120 MB | 0.8 | 131312 |
| 60 MB | 0.4 | 69856 |
| 30 MB | 0.2 | 38992 |
RSS 는 잡은 크기보다 커서 240 MB 가 약 254,000 KiB 였다(파이썬 자체가 쓰는 몫으로 보인다). 두 번째 실행에서는 RSS 가 48~160 KiB 달랐고 순서는 같았다.
ps -m -o rss= -p 번호들: RSS 내림차순.ps aux | sort -nrk 4: 4번째 열%MEM을 큰 수부터. 네 프로세스가 같은 순서.ps -A -o pid=,rss=,comm= | sort -k2 -nr: RSS 열을 큰 수부터. 같은 순서.
이어서 전체 프로세스(646줄)에서 ps -A -m -o rss= 를 세 번 돌려 줄마다 앞 줄보다 커지는 곳을 셌다. RSS·%MEM 열 모두 위반은 0이었다. ps -A -r -o %cpu= 도 세 번 모두 0이었다. 공개 글이 소개한 ps -er -o pid,pcpu,comm 과 거기서 -r 을 -m 으로 바꾼 ps -em -o pid,pmem,comm, 그리고 ps aux -m 도 각 열이 내림차순이었고(위반 0) ps aux -m 의 첫 줄은 그대로 헤더였다. -m 과 -r 은 서로 다른 기준이었다. 메모리 10 MB 를 잡고 40초 동안 계속 계산하는 프로세스를 다섯째로 더하자 ps -m 은 그 프로세스를 맨 끝에, ps -r 은 맨 앞에 놓았고 두 번의 실행이 같았다. -m 과 -r 을 함께 주면 마지막 옵션이 이겼다. 이 다섯 프로세스에서 ps -m -r 의 순서는 ps -r 과 같았고 ps -r -m 은 ps -m 과 같았다. top -l 1 -o mem 으로 같은 구성의 새 프로세스 네 개를 줄 세운 순서도 ps -m 과 같았다.
주의할 곳이 셋 있다. 첫째, sort 파이프는 헤더를 위로 두지 않는다. ps aux | sort -nrk 4 는 첫 줄이 데이터이고 헤더(USER ...)는 맨 끝으로 내려갔다. 헤더가 필요하면 ps aux -m 을 쓰고, 헤더가 필요 없으면 아래 등호 방식을 쓴다. 둘째, ps aux -m | head 처럼 head 로 자르면 head 가 먼저 끝나 ps 가 닫힌 파이프에 쓰다 종료 상태 141 로 끝났다(PIPESTATUS 가 141 0). 출력이 646줄이라 생긴 일일 수 있고, 프로세스가 적은 맥에서도 같은지는 시험하지 못했다. pipefail 을 켠 스크립트는 이것도 실패로 센다. 셋째, 값이 같은 줄끼리의 순서나 -m 이 정렬에 쓰는 정확한 값(RSS 인지 다른 지표인지)은 설명서에 한 줄뿐이라 내가 확인한 것은 RSS·%MEM 열이 내림차순이라는 결과까지다.
GNU 옵션 자리를 맥 옵션으로 바꾸기
시험한 것만 짝지으면 이렇다. 대신 줄은 모두 이 모양 그대로 돌려 종료 코드를 확인했다(ps aux -m | head 만 PIPESTATUS 가 141 0 이었고 나머지는 0). 열 순서는 리눅스 줄과 다르게 pid,pmem,comm 으로 적었으니 comm 이 마지막이어야 하면 그대로 쓴다.
| 리눅스에서 쓰던 줄 | 맥에서 시험한 대신 줄 |
|---|---|
ps aux --sort=-%mem | head |
ps aux -m | head |
ps -eo pid,comm,%mem --sort=-%mem |
ps -em -o pid,pmem,comm |
ps -eo pid,pcpu,comm --sort=-pcpu |
ps -er -o pid,pcpu,comm |
ps -p 1 --no-headers -o pid,comm |
ps -p 1 -o pid= -o comm= |
--no-headers 가 하는 일은 열 이름 뒤에 등호를 붙이면 된다. ps -o pid= -o comm= -p $$ 는 두 열짜리 한 줄이었고 첫 칸이 숫자(헤더 없음)였다. 등호를 빼면 첫 줄이 PID COMM 이었다.
그 줄에 같이 딸려 오는 것들
comm 열은 맥에서 경로를 통째로 낸다. 현재 셸에 ps -o comm= -p $$ 는 /bin/bash, 1번 프로세스는 /sbin/launchd 였고, -c 를 붙이면 bash, launchd 로 이름만 나왔다. 경로에 공백이 든 프로세스도 있었다. 내 맥에서 comm 만 뽑았을 때 단어가 둘 이상인 줄이 있었고, 처음 찾은 줄은 단어가 네 개였다. 그래서 ps -A -o pid=,comm= 출력을 awk 의 열 번호로 자르면 공백 있는 경로가 단어 단위로 나뉜다. comm 은 마지막 열로 두고 앞 열을 떼어 낸 나머지를 통째로 쓰는 편이 안전하다. 공백이 든 줄을 열 번호로 자르는 시험은 따로 하지 않았다.
etimes(경과 시간을 초로) 는 맥에 없다. 대신 etime 이 있다. 방금 띄운 프로세스는 01:06 처럼 분:초로, 1번 프로세스는 NN-NN:NN:NN 모양(일-시:분:초)으로 나왔다. 시:분:초만 있는 모양은 실제 프로세스로 보지 못했고 변환기에는 문자열로만 넣어 봤다. 초로 바꾸는 awk 는 다음과 같다.
etimes() { /bin/ps -o etime= -p "$1" | awk '{ d=0; t=$1; if (t ~ /-/) { split(t, x, "-"); d=x[1]; t=x[2] } n=split(t, a, ":"); s=0; for (i=1;i<=n;i++) s=s*60+a[i]; print d*86400+s }'; }
문자열만 넣어 시험하면 05 는 5, 01:05 는 65, 02:01:05 는 7265, 1-02:01:05 는 93665, 12-00:00:00 는 1036800 이었다. 실제 프로세스로는 sleep 70 을 띄우고 66초를 기다린 뒤 etime 이 01:06, 변환값이 66이었다. 1번 프로세스는 변환값이 (지금 - sysctl kern.boottime) 와 5초 안쪽으로 맞았다.
시험하지 못한 것
GNU ps 를 직접 돌려 맥과 줄 단위로 대조하지는 못했다. 리눅스에서 -m·r 이 어떻게 도는지, --sort 에 키를 여러 개 주는 (--sort=-%mem,pid) 경우의 맥 대체, --forest 의 맥 대체, 다른 macOS 버전, 스레드(-M) 출력의 정렬, 값이 같은 줄의 안정성, ps 가 쓰는 메모리 지표와 활동 상태 보기 앱 숫자의 관계, LC_ALL=C 가 아닌 로케일에서의 sort 동작은 시험하지 않았다. top -o mem 비교는 네 프로세스에서만 했다.
세 줄 요약
- 맥의 ps 는 –sort·–forest·–no-headers 를 종료 코드 1과 illegal option – - 로 거부하고, 오류를 버리면 빈 값이 0으로 끝난다.
- 메모리 순은 ps aux -m, CPU 순은 ps -er -o pid,pcpu,comm 이고 네 프로세스에서는 sort 파이프와 같은 순서, 전체 646줄에서는 내림차순이었다.
- 헤더는 -o pid= 로 없애고, etimes 는 etime 을 awk 로 초로 바꾸며, 같은 -m 이 GNU 설명서에서는 스레드 표시라는 점을 기억한다.
To help a reader who ran a Linux-style ps --sort line on a Mac and hit an error, or whose script hid the error and received an empty value, find a way to list processes by memory or CPU with the Mac's own ps.
The ps on this Mac (26.6.2) rejects GNU long options (the tested --sort, --forest, --no-headers, --pid, --version and --help) with exit code 1. Instead, ps aux -m sorts by memory descending and ps -er -o pid,pcpu,comm sorts by CPU descending, and on four processes with known sizes the order matched a sort pipe, while on all 646 lines of processes the output was descending. To drop the header, add an equals sign as in -o pid=, and turn etime into seconds with awk in place of etimes.
Replace the ps --sort lines in your scripts with ps aux -m or ps -em -o pid,pmem,comm, and check that nothing discards the error with 2>/dev/null and that pipefail is turned on.
Contents
One-line summary: The Mac’s ps rejects –sort with exit code 1, but ps aux -m sorts by memory descending and ps -er -o pid,pcpu,comm sorts by CPU descending, so switch to that form.
If you run ps aux --sort=-%mem | head, which you used on Linux to find the processes using the most memory, in a Mac terminal, you get an error and a usage message instead of a list. This article shows, by running them on this Mac, how far you can trust the methods that line processes up the same way with the Mac’s own ps, why a script that hides the error silently receives an empty value, and that the same -m means something else on Linux.
/bin/ps: illegal option -- -
usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]]
The environment was /bin/ps on macOS 26.6.2 arm64 with bash 3.2.57, on 2026-10-30. I ran three test scripts twice each and the second result matched the first. The only differences were the process memory numbers (48 to 160 KiB). The test that counted all processes saw 646 lines both times. There is no GNU ps on this Mac (procps is not installed) to use as a baseline, so what I say about the Linux side comes from reading the procps-ng ps(1) manual (man7.org, 2025-04-23 edition), not from running it. A public article gives the same method. Apple Gazette’s introduction to the ps command says ps -er -o pid,pcpu,comm sorts by CPU and that you use -m instead of -r for memory.
A few terms. GNU is the command collection many Linux distributions use, and Mac commands belong to the BSD family, so the same name can take different options. An exit code is the number a command leaves when it ends, and 0 means success. RSS is the size a process currently holds in real memory (in KiB), and %MEM is the share of total memory that size takes up. pipefail is a shell setting that counts the whole pipeline as failed when a middle command fails.
Options the Mac ps rejects and options it accepts
I added the options one at a time and measured the exit code. The Mac rejected every GNU long option I tried with the same sentence and exit code 1. The error does not say which option is the problem: the first lines of ps --sort, ps --forest and ps --pid=1 were all the same illegal option -- -.
| Option | Mac /bin/ps |
|---|---|
--sort=-%mem, --sort=-pcpu, --sort=-rss |
1 (illegal option -- -) |
--forest, --no-headers, --pid 1, --version, --help |
1 (illegal option -- -) |
-o etimes, -o nlwp, -o thcount |
1 (keyword not found) |
-o %mem,%cpu, -o pcpu,pmem, -o rss,vsz,comm, -o args |
0 |
aux, -m, -r, -A -m |
0 |
The last two rows are the solution in this article. The Mac manual (man ps) describes -m as “sort by memory usage, instead of the combination of controlling terminal and process ID” and -r as “sort by current CPU usage”. The GNU ps manual describes the same letters differently. -m is “Show threads after processes”, and r, written BSD style without a dash, is “Restrict the selection to only running processes”. So if you take the Mac-style ps aux -m to a Linux server, it may not sort at all and may add threads instead. That part is from reading the manual; I could not run it on Linux.
Discarding the error lets an empty value pass as success
I measured what happens when you add 2>/dev/null because the error screen looks messy. ps aux --sort=-%mem 2>/dev/null | head -3 printed nothing (the result string had length 0). PIPESTATUS, which collects the exit status of each pipeline stage, was 1 0, and without pipefail the whole pipeline ended with the 0 from head ($? was 0). With pipefail on, the whole pipeline was 1. So if a script that stored “names of the processes using the most memory” in a variable gets that variable back empty after moving to a Mac, suspect 2>/dev/null and the missing pipefail first.
Lining processes up with the Mac ps, and how far to trust it
I made four processes with known memory sizes. They are Python processes that hold 30, 60, 120 and 240 MB and sleep for 40 seconds. The three methods below lined all four processes up in the same order (240, 120, 60, 30).
| Memory held | %MEM |
RSS (KiB, one run) |
|---|---|---|
| 240 MB | 1.5 | 254048 |
| 120 MB | 0.8 | 131312 |
| 60 MB | 0.4 | 69856 |
| 30 MB | 0.2 | 38992 |
RSS was larger than the size held, so 240 MB came out at about 254,000 KiB (it looks like the share Python itself uses). In the second run RSS differed by 48 to 160 KiB and the order was the same.
ps -m -o rss= -p pids: RSS descending.ps aux | sort -nrk 4: the 4th column%MEM, largest first. The four processes came out in the same order.ps -A -o pid=,rss=,comm= | sort -k2 -nr: the RSS column, largest first. Same order.
Next I ran ps -A -m -o rss= three times over all processes (646 lines) and counted the places where a line was larger than the line before it. Both the RSS and %MEM columns had 0 violations. ps -A -r -o %cpu= was 0 in all three runs as well. ps -er -o pid,pcpu,comm from the public article, ps -em -o pid,pmem,comm (which swaps -r for -m), and ps aux -m were also descending in each column (0 violations), and the first line of ps aux -m was still the header. -m and -r turned out to be different criteria. When I added a fifth process that held 10 MB and kept computing for 40 seconds, ps -m put it last and ps -r put it first, identically in both runs. When -m and -r were given together, the last option won. On these five processes the order of ps -m -r was the same as ps -r, and ps -r -m was the same as ps -m. The order from top -l 1 -o mem on a new set of four processes of the same makeup also matched ps -m.
There are three places to be careful. First, a sort pipe does not keep the header on top. ps aux | sort -nrk 4 starts with a data line, and the header (USER ...) dropped to the very end. If you need the header, use ps aux -m; if you do not, use the equals-sign method below. Second, when you cut with head as in ps aux -m | head, head finishes first and ps writes into a closed pipe and ended with status 141 (PIPESTATUS was 141 0). That may have happened because the output is 646 lines, and I could not test whether it is the same on a Mac with fewer processes. A script with pipefail on counts that as a failure too. Third, the order among lines with equal values and the exact value -m sorts on (RSS or some other measure) get only one line in the manual, so what I confirmed is only the result that the RSS and %MEM columns are descending.
Swapping the GNU option spots for Mac options
Pairing only what I tested gives this. I ran every replacement line in exactly this form and checked the exit code (only ps aux -m | head had a PIPESTATUS of 141 0; the rest were 0). The column order is pid,pmem,comm, unlike the Linux line, so keep it as is when comm must come last.
| Line you used on Linux | Replacement tested on the Mac |
|---|---|
ps aux --sort=-%mem | head |
ps aux -m | head |
ps -eo pid,comm,%mem --sort=-%mem |
ps -em -o pid,pmem,comm |
ps -eo pid,pcpu,comm --sort=-pcpu |
ps -er -o pid,pcpu,comm |
ps -p 1 --no-headers -o pid,comm |
ps -p 1 -o pid= -o comm= |
What --no-headers does is done by adding an equals sign after the column name. ps -o pid= -o comm= -p $$ was a single line with two columns, and its first field was a number (no header). Without the equals sign the first line was PID COMM.
Things that come along with that line
The comm column prints the whole path on the Mac. For the current shell ps -o comm= -p $$ gave /bin/bash and process 1 gave /sbin/launchd, and with -c only the names bash and launchd came out. Some processes also have spaces in the path. When I pulled only comm on my Mac, some lines had two or more words, and the first one I found had four words. So if you cut the output of ps -A -o pid=,comm= by awk column number, paths with spaces are split into words. It is safer to keep comm as the last column and use everything that remains after removing the leading columns whole. I did not run a separate test that cuts lines with spaces by column number.
etimes (elapsed time in seconds) does not exist on the Mac. Instead there is etime. A process I had just started showed it as minutes:seconds like 01:06, and process 1 showed the NN-NN:NN:NN shape (days-hours:minutes:seconds). I did not see the hours:minutes:seconds-only shape on a real process and fed it to the converter only as a string. An awk that turns it into seconds looks like this.
etimes() { /bin/ps -o etime= -p "$1" | awk '{ d=0; t=$1; if (t ~ /-/) { split(t, x, "-"); d=x[1]; t=x[2] } n=split(t, a, ":"); s=0; for (i=1;i<=n;i++) s=s*60+a[i]; print d*86400+s }'; }
Feeding it strings alone gave 5 for 05, 65 for 01:05, 7265 for 02:01:05, 93665 for 1-02:01:05 and 1036800 for 12-00:00:00. With a real process, I started sleep 70 and waited 66 seconds, and etime was 01:06 with a converted value of 66. For process 1, the converted value matched (now minus sysctl kern.boottime) to within 5 seconds.
What I could not test
I could not run GNU ps and compare it with the Mac line by line. I did not test how -m and r behave on Linux, a Mac substitute for giving --sort several keys (--sort=-%mem,pid), a Mac substitute for --forest, other macOS versions, the sorting of thread (-M) output, the stability of lines with equal values, how the memory measure ps uses relates to the numbers in the Activity Monitor app, or how sort behaves in locales other than LC_ALL=C. The top -o mem comparison was done only on the four processes.
Three-line summary
- The Mac’s ps rejects –sort, –forest and –no-headers with exit code 1 and illegal option – -, and if you discard the error an empty value ends with 0.
- ps aux -m is memory order and ps -er -o pid,pcpu,comm is CPU order, and on four processes both gave the same order as a sort pipe, and on all 646 lines of processes both were descending.
- Drop the header with -o pid=, turn etime into seconds with awk in place of etimes, and remember that the same -m is thread display in the GNU manual.