{"id":20649250,"url":"https://github.com/marcolucidi01/after","last_synced_at":"2026-04-22T06:02:23.795Z","repository":{"id":193649488,"uuid":"421380262","full_name":"MarcoLucidi01/after","owner":"MarcoLucidi01","description":"run a command after a process terminates","archived":false,"fork":false,"pushed_at":"2021-11-05T16:45:37.000Z","size":4,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-09T19:16:50.093Z","etag":null,"topics":["linux","pidfd","process","wait"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MarcoLucidi01.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-10-26T10:31:22.000Z","updated_at":"2021-11-22T20:14:47.000Z","dependencies_parsed_at":"2023-09-09T08:29:23.588Z","dependency_job_id":"3d327a8a-5632-4cab-a24a-1710f8e686ea","html_url":"https://github.com/MarcoLucidi01/after","commit_stats":null,"previous_names":["marcolucidi01/after"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MarcoLucidi01/after","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcoLucidi01%2Fafter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcoLucidi01%2Fafter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcoLucidi01%2Fafter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcoLucidi01%2Fafter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarcoLucidi01","download_url":"https://codeload.github.com/MarcoLucidi01/after/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcoLucidi01%2Fafter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32123604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T00:31:26.853Z","status":"online","status_checked_at":"2026-04-22T02:00:05.693Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["linux","pidfd","process","wait"],"created_at":"2024-11-16T17:13:20.823Z","updated_at":"2026-04-22T06:02:23.749Z","avatar_url":"https://github.com/MarcoLucidi01.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"after\n=====\n\nrun a command *after* a process terminates.\n\nI often remember too late to chain commands to long running jobs and this small\ntool allows me to avoid to stop and re-run the job to chain something to it.\n\nfor example, I can get a pop-up when this slow download is finished:\n\n    $ after $(pgrep -f youtube-dl) gxmessage \"video download finished!\"\n\nor I can turn off my computer after the backup is done:\n\n    $ after $(pgrep backup) systemctl poweroff\n\nhere `backup` could have been started by `cron` because `after` is not limited\nto processes executed from the current shell/session/terminal/user but it can\n\"wait\" (not in the UNIX sense, see below) for *any* process.\n\nthe general usage is:\n\n    $ after -h\n    after: usage: after pid [cmd] [cmdargs...]\n\n`cmd` is not required, if missing, `after` will still block until the process\nterminates and you can chain commands using shell syntax (this is also useful\nfor using shell completion feature while typing the command) e.g.:\n\n    $ after $(pgrep sleep) \u0026\u0026 echo hello \u0026\u0026 printf \"world\\n\"\n    hello\n    world\n    $\n\nbut please remember that the exit status of `after` is **not** the exit status\nof the \"waited\" process: `after` does not `wait()` for a process in the UNIX\nsense, it merely gets notified when the process exits and then calls\n`execvp(cmd)` (if `cmd` is present).\n\ninstall\n-------\n\nclone the repo and build and install with your usual `make install`. you can\nchange `PREFIX` if you want, default is `/usr/local` which puts the binary in\n`/usr/local/bin`.\n\nBUGS (features?)\n----------------\n\n- **NOT PORTABLE!** `after` only runs on (recent) Linux (`\u003e= 5.3`). it's\n  implemented using the new [`pidfd_open()`][1] syscall/api which:\n\n  \u003e creates a file descriptor that refers to the process whose PID is specified\n  \u003e in pid.\n\n  `pidfd`s are cool because they are stable, private handles to processes (i.e.\n  no pid recycling problems) and are `poll`alble!\n\n  \u003e A PID file descriptor can be monitored using `poll(2)`, `select(2)`, and\n  \u003e `epoll(7)`.  When the process that it refers to terminates, these interfaces\n  \u003e indicate the file descriptor as readable. Note, however, that in the current\n  \u003e implementation, nothing can be read from the file descriptor (`read(2)` on\n  \u003e the file descriptor fails with the error `EINVAL`).\n\n  `poll()` support was added in kernel `5.3`, which is good considering that\n  current Debian stable is on `5.10`.\n\n  to be honest, the core functionality of `after` was already there in the man\n  page of `pidfd_open()` shown as example, I \"stole\" it from there eheheh :)\n\n- `after` **can't** get the exit status of the terminated process and use it to\n  *conditionally* chain other commands. this would be really nice to have, but\n  at the moment it is not possible to `wait()` on non-child processes, not even\n  with `pidfd`s. maybe it's possible to get the exit value by other means e.g.\n  `ptrace` but I'd like to stick with `pidfd` api and avoid additional overhead.\n\n- *but but all this can already be done using [insert-better-tool/shell-feature]!*\n  yes yes, I know, this is yet another tool that does roughly the same thing\n  using a new Linux api :)\n\n[1]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcolucidi01%2Fafter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcolucidi01%2Fafter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcolucidi01%2Fafter/lists"}