[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-94966":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":15,"starSnapshotCount":15,"syncStatus":33,"lastSyncTime":34,"discoverSource":35},94966,"lsoff","yutat23\u002Flsoff","yutat23","CLI \u002F TUI that lists listening TCP\u002FUDP ports","",null,"Go",163,5,104,0,41,66.43,"MIT License",false,"main",true,[23,24,25,26,27,28,29],"cli","golang","linux","lsof","macos","tui","windows","2026-08-24 04:01:23","# lsoff\n\n[English](README.md) | [日本語](README.ja.md)\n\n\u003Cimg width=\"899\" height=\"477\" alt=\"image\" src=\"https:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002F6cb1ff20-f44d-4759-b0e1-0d34ac629153\" \u002F>\n\nCLI \u002F TUI that lists listening TCP\u002FUDP ports on Windows, Linux, and macOS.\n\nThink of it as a port-focused `lsof`: quickly see who is holding a port, then kill the process if you need to.\n\n## Install\n\nBinaries are attached to [GitHub Releases](https:\u002F\u002Fgithub.com\u002Fyutat23\u002Flsoff\u002Freleases) (`lsoff-darwin-arm64`, `lsoff-linux-amd64`, `lsoff-windows-amd64.exe`, …).\n\nOn macOS or Linux, install it from the [Homebrew tap](https:\u002F\u002Fgithub.com\u002Fyutat23\u002Fhomebrew-tap). Homebrew 6 requires trusting a third-party tap first:\n\n```bash\nbrew tap yutat23\u002Ftap\nbrew trust yutat23\u002Ftap\nbrew install lsoff\n```\n\n```bash\ngo install github.com\u002Fyutat23\u002Flsoff@latest\n```\n\nOr:\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fyutat23\u002Flsoff\ncd lsoff\ngo build -o lsoff .\n```\n\nA tagged push (`git tag v0.1.0 && git push origin v0.1.0`) builds those binaries and publishes the release.\n\nmacOS uses libproc, so CGO is required (enabled by a normal `go build`).\n\n## Usage\n\n```bash\nlsoff                 # TUI (prints a table if stdout is not a TTY)\nlsoff 8080            # show processes holding port 8080\nlsoff nginx           # search by name, path, PID, cmdline, project, service…\nlsoff -q \"node 8080\"  # space-separated words are AND\nlsoff -t              # TCP only (TUI)\nlsoff -u 53           # UDP port 53\nlsoff --json nginx    # search results as JSON\nlsoff -k 8080         # kill those processes (with confirmation)\nlsoff -k -y 8080      # skip confirmation (required when piped)\nlsoff -h\nlsoff -v\n```\n\nExample output for a port query:\n\n```\nPROTO  PORT  ADDRESS      PID    PROJECT  PROCESS  PATH                 CMD                   CWD\ntcp    8080  127.0.0.1    41233  lsoff    node     \u002Fusr\u002Flocal\u002Fbin\u002Fnode  \u002Fusr\u002Flocal\u002Fbin\u002Fnode   ~\u002Fmywork\u002Flsoff\n```\n\n### TUI\n\n| Key \u002F action | What it does |\n|------|------|\n| `\u002F` \u002F click `Search:` \u002F `ctrl+f` | Search (port, PID, name, project, path, cmdline; spaces are AND) |\n| `↑` \u002F `↓` \u002F `j` \u002F `k` \u002F click \u002F wheel | Move and select (works while searching too) |\n| Click a header | Sort by that column (click again for descending) |\n| `s` \u002F `S` | Cycle sort column \u002F toggle ascending-descending |\n| `y` | Copy the selected `addr:port` |\n| `a` | Auto-refresh every 2 seconds |\n| `enter` \u002F `space` \u002F click `▸` | Expand or collapse sockets for the same PID |\n| `h` \u002F `l` | Collapse \u002F expand |\n| `esc` \u002F `ctrl+c` | Clear the search |\n| `r` | Reload |\n| `x` | Kill the selected process (asks first) |\n| `q` | Quit |\n\nIn the TUI, `tcp` is green and `udp` is amber. The selected row uses the highlight background instead. The CLI table stays uncolored so it stays script-friendly. Process names, command lines, and paths are sanitized for the terminal (control characters and ANSI\u002FOSC sequences). JSON keeps the original strings.\n\nSockets that share a PID (typical IPv4 + IPv6) start collapsed as one row with `▸` and a `+N` count. `enter` expands them.\n\nKnown service names (http, postgres, redis, vite, …) are searchable and shown on the `SVC` footer line. Ambiguous ports such as 3000 are aliases-only and have no single display name. Historic ports (echo, chargen) are not included. JSON may include `\"service\"` when a display name exists.\n\nAfter `x`, press `y` to confirm, or `n` \u002F `esc` to cancel. Kill verifies that the process is still the same one that was listed: Linux uses `pidfd_open` (the fd refers to that process, not the PID number), macOS checks `pbi_start_tvsec`\u002F`usec` then signals, and Windows checks `CreationTime` on an open process handle. On Unix it sends SIGTERM first, then SIGKILL if that same process is still alive after 2 seconds. On Windows it uses `TerminateProcess`. pid 1 and the lsoff process itself are never killed.\n\nCLI `-k` follows the same rules. If the same PID appears twice (IPv4 and IPv6), it is killed only once. When stdin is not a TTY, `-y` is required so a pipe cannot kill by accident.\n\n## Limitations\n\n- **macOS kill is not atomic.** There is no pidfd. lsoff re-reads `pbi_start_tvsec`\u002F`usec` immediately before `kill(2)`, but a PID can still be reused in that tiny window. Linux pidfd and Windows process handles do not have this gap.\n- **Windows cmdline\u002Fcwd** use `NtQueryInformationProcess`, which Microsoft documents as an internal API that may change. A 64-bit build reads WOW64 (32-bit) process strings from the 32-bit PEB; `ProcessCommandLineInformation` is parsed with the *caller's* pointer size, then PEB `CommandLine` is used as a target-bitness fallback. A 32-bit lsoff cannot inspect 64-bit processes' cmdline or cwd.\n- **Version** is baked in at `go build` time. Rebuild after pulling if `lsoff -v` disagrees with `main.go`.\n\n## How it collects data\n\nNo external commands (`lsof` \u002F `ss` \u002F `netstat`).\n\n| OS | API |\n|----|-----|\n| Linux | `\u002Fproc\u002Fnet\u002F{tcp,tcp6,udp,udp6}`, `\u002Fproc\u002F\u003Cpid>\u002F{fd,cmdline,cwd}` |\n| macOS | `libproc` (sockets and cwd) and `sysctl kern.procargs2` |\n| Windows | IP Helper, `QueryFullProcessImageName`, `NtQueryInformationProcess` (cmdline and cwd) |\n\nWithout permission, PID, path, and cmdline may be empty. Run as root \u002F Administrator in that case.\n\nUDP has no LISTEN state, so sockets bound to a port with no remote peer are shown.\n\n## License\n\nMIT\n","lsoff 是一个跨平台的命令行与终端用户界面（TUI）工具，用于快速列出当前系统中监听 TCP\u002FUDP 端口的进程。它支持 Windows、Linux 和 macOS，提供端口过滤、进程名\u002F路径\u002FPID 模糊搜索、按列排序、实时刷新、JSON 输出及交互式杀进程等功能；底层基于 Go 编写，利用各平台原生接口（如 Linux 的 \u002Fproc、macOS 的 libproc）获取 socket 信息，兼顾性能与可移植性。适用于开发调试、端口冲突排查、服务管理等运维与开发场景。",2,"2026-08-19 02:30:03","CREATED_QUERY"]