Linux 指令学习
来源:Linux 命令行操作
一、创建用户与 sudo 权限
1. 创建新用户
sudo adduser 用户名adduser 是交互式命令,会自动创建用户目录、设置密码等信息。
如果只需要简单创建用户(不带交互):
sudo useradd -m 用户名-m→--create-home→ 自动创建用户的家目录(/home/用户名)
创建后手动设置密码:
sudo passwd 用户名2. 给用户添加 sudo 权限
方式一:加入 sudo 组(推荐)
sudo usermod -aG sudo 用户名-a→--append→ 追加到附加组(不覆盖原有组)-G→--groups→ 指定附加组sudo→ 组名,加入该组即拥有 sudo 权限
方式二:直接编辑 sudoers 文件
sudo visudo在文件末尾添加:
用户名 ALL=(ALL:ALL) ALL3. 验证 sudo 权限
切换到该用户并测试:
su - 用户名
sudo whoami如果输出 root,说明 sudo 权限已生效。
4. 其他用户管理命令
| 操作 | 命令 |
|---|---|
| 删除用户 | sudo userdel 用户名 |
| 删除用户及家目录 | sudo userdel -r 用户名 |
| 修改用户名 | sudo usermod -l 新名 旧名 |
| 锁定用户 | sudo usermod -L 用户名 |
| 解锁用户 | sudo usermod -U 用户名 |
| 查看用户所属组 | groups 用户名 |
| 查看用户信息 | id 用户名 |
常用参数
-m→--create-home→ 创建家目录-a→--append→ 追加模式(与 -G 配合使用)-G→--groups→ 指定附加组-r→--remove→ 同时删除用户家目录(userdel)-l→--login→ 指定新用户名(usermod)-L→--lock→ 锁定用户账户-U→--unlock→ 解锁用户账户
二、SCP 命令用法
核心概念
SCP(Secure Copy Protocol)用于在服务器之间安全地复制文件,基于 SSH 协议。
基本语法
scp [选项] 源路径 目标路径常见用法
| 场景 | 命令 |
|---|---|
| 从另一个用户复制文件 | scp 用户名@localhost:/home/用户名/文件 ./ |
| 复制整个目录 | scp -r 用户名@localhost:/home/用户名/目录 ./ |
| 复制到另一个用户 | scp 文件 用户名@localhost:/home/用户名/ |
| 指定端口 | scp -P 22 文件 用户名@localhost:/路径 |
常用参数
-r→recursive→ 递归复制整个目录-P→port→ 指定 SSH 端口-v→verbose→ 显示详细传输信息-C→compression→ 启用压缩传输
使用场景
- 同一服务器不同用户间复制文件
- 跨服务器传输文件
- 备份重要数据到其他位置
三、内核日志查看命令
1. dmesg — 内核消息查看
核心概念
dmesg (display message) 用于显示内核环形缓冲区(kernel ring buffer)中的消息,包括硬件检测、驱动加载、系统错误等。
基本语法
dmesg [选项]常用参数
-T→human-readable→ 显示人类可读的时间戳-w→wait→ 实时监控新内核消息(类似 tail -f)-l→level→ 按级别过滤(如 err、warn、info)
常见用法
| 场景 | 命令 |
|---|---|
| 查看最近50条消息 | dmesg -T | tail -50 |
| 只看错误 | dmesg -T -l err |
| 实时监控 | dmesg -w |
| 查看 USB 设备 | dmesg -T | grep -i usb |
| 查看磁盘错误 | dmesg -T | grep -i error |
使用场景
- 排查硬件问题(USB 无法识别、磁盘错误)
- 检查驱动加载情况
- 诊断网络设备故障
2. journalctl — systemd 日志查询
核心概念
journalctl 是 systemd 的日志查询工具,日志持久化存储,可查看历史启动记录。
基本语法
journalctl [选项]常用参数
-k→kernel→ 只显示内核消息(类似 dmesg)-b→boot→ 按启动次数过滤(-0 当前,-1 上次)-f→follow→ 实时追踪日志-u→unit→ 按服务单元过滤-p→priority→ 按优先级过滤(如 err、warning)-n→lines→ 显示最近 N 行
常见用法
| 场景 | 命令 |
|---|---|
| 本次启动的内核日志 | sudo journalctl -k -b -0 |
| 上次启动的内核日志 | sudo journalctl -k -b -1 |
| 实时监控内核消息 | sudo journalctl -k -b -0 -f |
| 查看某个服务日志 | journalctl -u nginx |
| 只看错误 | journalctl -p err |
使用场景
- 查看历史启动的内核消息(dmesg 做不到)
- 按服务排查问题
- 分析系统崩溃原因
3. dmesg vs journalctl 对比
| 特性 | dmesg | journalctl |
|---|---|---|
| 日志持久化 | ❌ 重启清空 | ✅ 持久存储 |
| 查看历史启动 | ❌ | ✅ |
| 语法简单度 | 简单 | 更灵活 |
| 需要 sudo | 通常不需要 | 查看其他用户日志需要 |
选择建议
- 快速查看当前硬件问题 →
dmesg - 需要查看历史日志 →
journalctl - 按服务查日志 →
journalctl -u 服务名
四、进程查看命令
1. ps — 进程快照
核心概念
ps (process status) 用于查看某一瞬间的进程状态,输出一次即结束。适合快速查找进程信息。
基本语法
ps [选项]常用参数
-e→every→ 显示所有进程-f→full→ 显示完整格式(含 UID、PID、PPID 等)-a→all→ 显示所有用户的进程(不包括会话领导者)-u→user→ 按用户格式显示,可指定用户名-x→ — → 包括无终端控制的进程
常见用法
| 场景 | 命令 |
|---|---|
| 查看所有进程(完整格式) | ps -ef |
| 查看所有进程(含 CPU/内存) | ps -aux |
| 查看指定用户的进程 | ps -u 用户名 |
| 查找特定进程 | ps -ef | grep 进程名 |
| 按 CPU 排序 | ps -aux --sort=-%cpu | head |
| 按内存排序 | ps -aux --sort=-%mem | head |
使用场景
- 快速查看某个进程是否存在
- 获取进程 PID 以便 kill
- 排查占用资源最高的进程
2. top — 实时进程监控
核心概念
top 用于实时监控系统进程状态,持续刷新显示 CPU、内存使用情况。支持交互操作。
基本语法
top [选项]常用参数
-u→user→ 只显示指定用户的进程-d→delay→ 设置刷新间隔(秒)-n→iterations→ 刷新 N 次后退出-p→pid→ 只监控指定 PID
交互快捷键(运行中按)
| 按键 | 功能 |
|---|---|
P | 按 CPU 使用率排序 |
M | 按内存使用率排序 |
k | 杀死进程(输入 PID) |
q | 退出 top |
1 | 显示每个 CPU 核心的使用率 |
h | 显示帮助 |
输出字段缩写
| 缩写 | 英文全称/来源 | 含义 |
|---|---|---|
PID | Process ID | 进程编号 |
USER | User | 运行该进程的用户 |
PR | Priority | 进程优先级 |
NI | Nice value | nice 值,影响进程调度优先级 |
VIRT | Virtual Memory | 虚拟内存总量,不等于真实物理内存占用 |
RES | Resident Memory / Resident Set Size | 常驻物理内存,查实际内存占用时重点看 |
SHR | Shared Memory | 共享内存 |
S | State / Status | 进程状态 |
%CPU | CPU Usage Percent | CPU 使用百分比 |
%MEM | Memory Usage Percent | 内存使用百分比 |
TIME+ | CPU Time | 进程累计使用 CPU 的时间 |
COMMAND | Command | 启动命令或进程名 |
NI 的 Nice 表示进程对其他进程的”友好程度”:值越高越愿意让出 CPU;值越低,调度优先级越高。
常见用法
| 场景 | 命令 |
|---|---|
| 实时监控所有进程 | top |
| 只看某用户进程 | top -u 用户名 |
| 只监控特定进程 | top -p PID |
| 每 2 秒刷新一次 | top -d 2 |
使用场景
- 实时观察系统资源使用情况
- 发现 CPU 或内存占用异常的进程
- 持续监控某个进程的资源变化
3. ps vs top 对比
| 特性 | ps | top |
|---|---|---|
| 数据类型 | 静态快照(某一瞬间) | 动态实时(持续刷新) |
| 输出方式 | 一次性输出,执行完退出 | 持续运行,实时更新 |
| 交互性 | 无交互 | 支持按键交互(排序、kill 等) |
| 资源占用 | 低(跑一次就结束) | 持续占用 CPU/内存 |
选择建议
- 查一次就够了 →
ps(如ps -ef \| grep nginx) - 需要持续观察 →
top(如实时看 CPU、内存变化)
排查问题的一般流程
- 先用
top看实时状态,找到可疑进程 - 再用
ps -ef \| grep 进程名获取详细信息 - 用
kill PID或kill -9 PID结束异常进程
五、aptitude 包管理器
1. 基本用法
核心概念
aptitude 是 Debian/Ubuntu 系统的包管理器,是 apt 的增强版,能更智能地处理复杂的依赖冲突。
名字来源
aptitude 不是缩写,而是英文单词,意为”才能、资质、适合性”。而 apt 是 Advanced Package Tool(高级包管理工具)的缩写。
基本语法
sudo aptitude [操作] [软件包名]常用操作
| 场景 | 命令 |
|---|---|
| 安装软件包 | sudo aptitude install XX |
| 卸载软件包 | sudo aptitude remove XX |
| 搜索软件包 | sudo aptitude search XX |
| 更新软件源 | sudo aptitude update |
| 安全升级 | sudo aptitude safe-upgrade |
2. aptitude vs apt 对比
| 特性 | apt | aptitude |
|---|---|---|
| 依赖处理 | 基础 | 更智能,能自动解决复杂依赖冲突 |
| 交互界面 | 无 | 有 ncurses 终端界面 |
| 安装推荐包 | 默认不装 | 默认会装 |
| 清理卸载 | 需手动 autoremove | 自动处理不需要的依赖 |
选择建议
- 日常使用 →
apt就够了 - 遇到棘手的依赖问题时 → 换
aptitude试试
六、systemctl 服务管理
1. 基本概念
systemctl = system + control,是 systemd 的核心管理命令。systemd 是现代 Linux 的初始化系统(PID 1),负责启动时激活服务、管理后台守护进程。
2. 服务管理基础命令
| 场景 | 命令 |
|---|---|
| 启动服务 | sudo systemctl start 服务名 |
| 停止服务 | sudo systemctl stop 服务名 |
| 重启服务 | sudo systemctl restart 服务名 |
| 重新加载配置(不中断) | sudo systemctl reload 服务名 |
| 查看服务状态 | systemctl status 服务名 |
| 开机自启 | sudo systemctl enable 服务名 |
| 禁止开机自启 | sudo systemctl disable 服务名 |
| 重新加载 systemd 配置 | sudo systemctl daemon-reload |
| 查看是否开机自启 | systemctl is-enabled 服务名 |
| 查看是否运行中 | systemctl is-active 服务名 |
常用参数
-t→type→ 按类型过滤(service、socket、device 等)-a→all→ 显示所有单元,包括未加载的-l→full→ 不截断输出(显示完整信息)-q→quiet→ 静默模式
reload vs restart 区别
| 操作 | 效果 | 适用场景 |
|---|---|---|
reload | 只重新加载配置,服务不中断 | 修改了配置文件 |
restart | 先停止再启动,会短暂中断 | 升级了程序、配置改动大 |
3. 查看服务列表
| 场景 | 命令 |
|---|---|
| 查看所有运行中的服务 | systemctl list-units --type=service |
| 查看所有已安装的服务 | systemctl list-unit-files --type=service |
| 查看失败的服务 | systemctl --failed |
| 查看服务的完整配置 | systemctl cat 服务名 |
| 查看服务依赖关系 | systemctl list-dependencies 服务名 |
4. 服务状态输出解读
● nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
Active: active (running) since Mon 2026-05-19 10:00:00 CST; 2h ago
Main PID: 1235 (nginx)
Tasks: 3 (limit: 4915)
Memory: 10.0M| 字段 | 含义 |
|---|---|
Loaded | 单元文件位置;enabled=开机自启,disabled=不开机自启 |
Active | active (running)=运行中;inactive (dead)=已停止;failed=失败 |
Main PID | 主进程 ID |
Memory | 内存占用 |
5. 系统状态控制
| 场景 | 命令 |
|---|---|
| 关机 | sudo systemctl poweroff |
| 重启 | sudo systemctl reboot |
| 挂起(睡眠) | sudo systemctl suspend |
| 休眠 | sudo systemctl hibernate |
6. 自定义开机自启服务(重点)
场景: 让自己的程序开机自启,或者被杀死后自动拉起。
步骤一:创建 service 文件
sudo vim /etc/systemd/system/myapp.service步骤二:写入配置
[Unit]
Description=我的应用
After=network.target # 在网络启动后再启动
[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/user/app.py # 启动命令
WorkingDirectory=/home/user # 工作目录
User=user # 运行用户
Restart=always # 关键:总是重启
RestartSec=5 # 重启间隔 5 秒
StartLimitIntervalSec=60 # 60 秒内
StartLimitBurst=5 # 最多重启 5 次(防无限重启)
[Install]
WantedBy=multi-user.target步骤三:启用并启动
sudo systemctl daemon-reload # 重新加载配置
sudo systemctl start myapp # 启动
sudo systemctl enable myapp # 开机自启
sudo systemctl status myapp # 查看状态Restart 策略
| 值 | 含义 |
|---|---|
no | 不自动重启(默认) |
always | 任何原因退出都重启 |
on-success | 正常退出(退出码 0)才重启 |
on-failure | 异常退出才重启 |
大多数场景用 always 或 on-failure。
防无限重启
StartLimitIntervalSec=60 # 时间窗口 60 秒
StartLimitBurst=5 # 最多重启 5 次60 秒内重启超过 5 次后,systemd 会停止尝试,需要手动 systemctl restart myapp 重置计数。
路径说明
| 目录 | 用途 |
|---|---|
/etc/systemd/system/ | 用户自定义服务(推荐放这里) |
/lib/systemd/system/ | 软件包安装的服务(不要手动改) |
7. 使用场景
- 管理 Web 服务器(nginx、apache)
- 管理数据库服务(mysql、postgresql)
- 管理容器服务(docker)
- 让自己的程序开机自启、崩溃自动重启
七、查看内存与存储
1. free -h — 查看内存总体使用情况
free -h
free -h -s 2 # 每 2 秒刷新一次| 字段 | 含义 |
|---|---|
total | 总内存 |
used | 已使用内存 |
free | 完全空闲内存 |
buff/cache | 被缓存占用但可回收的内存 |
available | 估算当前还能给程序使用的内存,日常重点看这个 |
-h→human-readable→ 以 K/M/G 等人类可读单位显示-s→seconds→ 按秒持续刷新
2. top — 实时查看内存占用
top运行中按 M 可按内存使用率排序。想快速看占用最高的进程,也可以用:
ps aux --sort=-%mem | headps→ process status(进程状态)a→all users→ 显示所有用户的进程u→user-oriented→ 用面向用户的格式显示(包含 CPU、内存等)x→ 无固定英文全称,表示包含没有终端控制的后台进程--sort=-%mem→ 按内存占用倒序排序,-表示从大到小head→ 只显示前 10 行top运行中按M→ Memory,按内存占用排序
3. vmstat — 查看内存、CPU、IO 概览
vmstat 1 5 # 每 1 秒输出一次,共 5 次vmstat→ virtual memory statistics(虚拟内存统计)
常看字段:
| 字段 | 含义 |
|---|---|
free | 空闲内存 |
buff | buffer 占用 |
cache | cache 占用 |
si | swap in,从 swap 读回内存 |
so | swap out,写入 swap |
如果 si、so 长时间不为 0,通常说明内存压力较大。
4. swapon -s — 查看 swap 使用情况
swapon -s
free -hswapon -s 查看 swap 分区或 swap 文件列表;free -h 的 Swap 行可以快速看总量和已用量。
swapon→swap on,启用或查看 swap-s→summary,汇总显示 swap 列表
5. ls -lh — 查看文件大小
ls -lh| 参数 | 缩写含义 | 说明 |
|---|---|---|
-l | long | 长格式显示(含权限、大小等详细信息) |
-h | human-readable | 以 K/M/G 等人类可读单位显示 |
6. du -sh — 查看文件/目录的磁盘占用
du -sh * # 查看当前目录下每个文件/文件夹的占用
du -sh . # 只看当前目录总大小
du -h --max-depth=1 /var | sort -hdu→ disk usage(磁盘使用量)
| 参数 | 缩写含义 | 说明 |
|---|---|---|
-s | summary | 只显示总计,不递归列出子项 |
-h | human-readable | 以 K/M/G 等人类可读单位显示 |
-a | all | 显示所有文件和目录 |
--max-depth=1 | — | 只统计下一层目录,适合定位哪个目录占空间 |
7. df -h — 查看磁盘分区剩余空间
df -h # 查看所有挂载分区的使用情况
df -hT # 同时显示文件系统类型
df -ih # 查看 inode 使用情况df→ disk free(磁盘剩余空间)
| 参数 | 缩写含义 | 说明 |
|---|---|---|
-h | human-readable | 以 K/M/G 等人类可读单位显示 |
-T | type | 显示文件系统类型 |
-i | inode | 查看 inode 使用情况,小文件过多时重点看 |
8. lsblk — 查看磁盘和分区结构
lsblk
lsblk -f # 显示文件系统、UUID、挂载点lsblk→ list blk(block devices,块设备)-f→filesystem→ 显示文件系统、UUID、挂载点等信息
适合确认机器上有哪些磁盘、分区分别挂载到了哪里。
9. 按大小排序
ls -lhS
du -ah . | sort -h | tail -20ls -lhS→-S是size,按文件大小排序(大的在前)du -ah .→-a是all,同时列出文件和目录sort -h→human-readable,按 K/M/G 这类单位正确排序tail -20→ 只看最后 20 行,也就是排序后最大的 20 个文件/目录
10. ls、du、df 的区别
| 命令 | 缩写 | 显示内容 | 适用场景 |
|---|---|---|---|
ls -lh | — | 文件本身的大小 | 快速查看文件大小 |
du -sh | disk usage | 文件/目录实际占用的磁盘空间 | 查看某个目录占了多少空间 |
df -h | disk free | 磁盘分区的整体使用和剩余空间 | 查看磁盘还剩多少空间 |
lsblk | list block devices | 磁盘、分区、挂载点结构 | 查看磁盘设备和挂载关系 |
简单说:free/top 看内存,ls 看文件大小,du 看”谁占了空间”,df 看”还剩多少空间”,lsblk 看”磁盘怎么分区和挂载”。
八、kill 与 kill -9 的区别
1. 信号对比
kill PID (SIGTERM) | kill -9 PID (SIGKILL) | |
|---|---|---|
| 信号编号 | 15 | 9 |
| 能否被程序捕获/忽略 | 能 | 不能 |
| 程序能否做清理工作 | 能(保存数据、关闭连接等) | 不能,直接被内核干掉 |
| 什么时候有效 | 进程正常运行时 | 几乎所有情况 |
| 适用场景 | 先礼后兵,优先用这个 | SIGTERM 没用时的最后手段 |
kill= 跟进程说”请你退出” → 进程可以选择优雅退出kill -9= 内核直接把进程从系统中移除 → 连反应的机会都没有
2. 推荐流程
先 kill,等几秒没反应再 kill -9。直接 kill -9 可能导致数据丢失(比如正在写文件被强制中断)。
3. 杀不掉进程的排查
查看进程状态:
ps -p <PID> -o pid,stat,comm| 状态 | 含义 | 处理方式 |
|---|---|---|
T (Traced/Stopped) | 被调试器 attach 或 job control 暂停 | 先 kill -CONT 恢复再 kill -9 |
D (Uninterruptible Sleep) | 不可中断睡眠,通常等待 I/O | 检查磁盘/NFS 是否挂死 |
Z (Zombie) | 僵尸进程,已死但父进程未回收 | 杀父进程 |
排查步骤:
# 检查是否被调试器 attach
cat /proc/<PID>/status | grep TracerPid
# 如果 TracerPid 不为 0,先杀 tracer
kill -9 <TracerPid>
# T 状态进程:先恢复再强杀
kill -CONT <PID>
kill -9 <PID>九、pkill 与 kill 信号用法
1. kill 发送信号
kill -<信号> <PID>| 信号 | 编号 | 作用 | 示例 |
|---|---|---|---|
| SIGHUP | 1 | 热重载配置文件,不重启进程 | kill -1 1234 |
| SIGINT | 2 | 等同 Ctrl+C,中断进程 | kill -2 1234 |
| SIGQUIT | 3 | 类似 SIGINT,但会生成 core dump | kill -3 1234 |
| SIGTERM | 15 | 优雅退出(默认信号) | kill 1234 |
| SIGKILL | 9 | 强制杀死,不可捕获 | kill -9 1234 |
| SIGSTOP | 19 | 暂停进程,不可捕获 | kill -STOP 1234 |
| SIGCONT | 18 | 恢复被暂停的进程 | kill -CONT 1234 |
| SIGUSR1 | 10 | 用户自定义信号 1 | kill -10 1234 |
| SIGUSR2 | 12 | 用户自定义信号 2 | kill -12 1234 |
三种写法等价:
kill -1 1234 # 数字形式
kill -HUP 1234 # 名称形式
kill -s HUP 1234 # -s 显式指定典型场景:
# 让 nginx 重新加载配置
kill -1 $(cat /var/run/nginx.pid)
# 暂停一个吃 CPU 的进程,排查完再恢复
kill -STOP 5678
kill -CONT 5678
# 给自己写的程序发自定义信号,触发特定行为
kill -USR1 99992. pkill 按名字杀进程
pkill [选项] <模式>| 选项 | 作用 | 示例 |
|---|---|---|
-f | 匹配完整命令行(含参数) | pkill -f "python app.py" |
-x | 精确匹配进程名 | pkill -x nginx |
-i | 忽略大小写 | pkill -i Python |
-n | 只匹配最新的那个进程 | pkill -n python |
-o | 只匹配最老的那个进程 | pkill -o python |
-u user | 只杀指定用户的进程 | pkill -u www python |
-signal | 指定信号(默认 SIGTERM) | pkill -9 -f python |
常见用法:
# 杀掉所有 python 进程
pkill -f python
# 精确杀 nginx(不会误杀 nginx: worker)
pkill -x nginx
# 杀掉某个用户的所有进程
pkill -u testuser
# 只杀最新的 node 进程
pkill -n node
# 强制杀掉包含 "gunicorn" 的所有进程
pkill -9 -f gunicorn配套查询命令:
pgrep -f python # 查看匹配的 PID(不杀,只看)
pgrep -af python # -a 显示完整命令行3. killall 按进程名精确杀
killall nginx # 杀掉所有名为 nginx 的进程
killall -9 python # 强制杀
killall -u user nginx # 只杀某用户的pkill vs killall:
| pkill | killall | |
|---|---|---|
| 默认匹配 | 支持正则 | 精确匹配进程名 |
-f 选项 | 匹配完整命令行 | 无 |
| 轻量程度 | 更轻量 | 稍重 |
十、软链接 ln -s
1. 怎么创建软链接
软链接类似 Windows 里的快捷方式,用来给一个真实文件或目录创建另一个入口。
基本语法:
ln -s 源文件路径 软链接路径顺序不要写反:
ln -s 真实文件 想创建的链接例如,把程序保留在原目录,只在 /usr/local/bin 下创建一个命令入口:
sudo ln -s /home/ubuntu/software/codex-monitor/codex-token-monitor-linux-x86_64 /usr/local/bin/codex-monitor如果链接已经存在,可以用 -f 覆盖:
sudo ln -sf /home/ubuntu/software/codex-monitor/codex-token-monitor-linux-x86_64 /usr/local/bin/codex-monitor2. 为什么推荐源路径写绝对路径
创建软链接时,源文件路径最好写绝对路径,例如:
/home/ubuntu/software/codex-monitor/codex-token-monitor-linux-x86_64原因是:软链接里的相对路径是相对于软链接所在目录解析的,不是相对于执行命令时的当前目录。
比如这条命令容易出错:
sudo ln -sf codex-monitor /usr/local/bin/codex-monitor它会创建出类似这样的链接:
/usr/local/bin/codex-monitor -> codex-monitor因为链接本身就在 /usr/local/bin 里,codex-monitor 会被解析成 /usr/local/bin/codex-monitor,等于指向自己,形成循环链接。
所以实际使用时,推荐写成:
sudo ln -sf /home/ubuntu/software/codex-monitor/codex-token-monitor-linux-x86_64 /usr/local/bin/codex-monitor或者在源文件所在目录下,用 $(pwd) 自动生成绝对路径:
sudo ln -sf "$(pwd)/codex-token-monitor-linux-x86_64" /usr/local/bin/codex-monitor