mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-12 04:58:57 +00:00
parent
f52708a20f
commit
4fde67fa50
6 changed files with 122 additions and 0 deletions
|
@ -1,5 +1,11 @@
|
|||
# fish 2.6.0 (released ???)
|
||||
|
||||
## Notable fixes and improvements
|
||||
|
||||
- Jobs running in the background can now be removed from the list of jobs with the new `disown` builtin, which behaves like the same command in other shells (#2810).
|
||||
|
||||
## Other significant changes
|
||||
|
||||
- The `export` and `setenv` commands now supports colon-separated `PATH`, `CDPATH` and `MANPATH`.
|
||||
- The `read` command now has a default limit of 10 MiB. If a line is longer than that it will fail with $status set to 122 and the var will be empty. You can set a different limit by setting the FISH_READ_BYTE_LIMIT variable.
|
||||
- `read` now supports the `--silent` flag to hide the characters typed (#838).
|
||||
|
|
26
doc_src/disown.txt
Normal file
26
doc_src/disown.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
\section disown disown - remove a process from the list of jobs
|
||||
|
||||
\subsection disown-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
disown [ PID ... ]
|
||||
\endfish
|
||||
|
||||
\subsection disown-description Description
|
||||
|
||||
`disown` removes the specified <a href="index.html#syntax-job-control">job</a> from the list of jobs. The job itself continues to exist, but fish does not keep track of it any longer.
|
||||
|
||||
Jobs in the list of jobs are sent a hang-up signal when fish terminates, which usually causes the job to terminate; `disown` allows these processes to continue regardless.
|
||||
|
||||
If no process is specified, the most recently-used job is removed (like `bg` and `fg`). If one or more `PID`s are specified, jobs with the specified process IDs are removed from the job list. Invalid jobs are ignored and a warning is printed.
|
||||
|
||||
If a job is stopped, it is sent a signal to continue running, and a warning is printed. It is not possible to use the `bg` builtin to continue a job once it has been disowned.
|
||||
|
||||
The PID of the desired process is usually found by using <a href="index.html#expand-process">process expansion</a>, which can specify jobs or search by process name.
|
||||
|
||||
`disown` returns 0 if all specified jobs were disowned successfully, and 1 if any problems were encountered.
|
||||
|
||||
\subsection disown-example Example
|
||||
|
||||
`firefox &; disown` will start the Firefox web browser in the background and remove it from the job list, meaning it will not be closed when the fish process is closed.
|
||||
|
||||
`disown (jobs -p)` removes all jobs from the job list without terminating them.
|
|
@ -3058,6 +3058,86 @@ static int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
return res;
|
||||
}
|
||||
|
||||
/// Helper for builtin_disown
|
||||
static int disown_job(parser_t &parser, io_streams_t &streams, job_t *j) {
|
||||
if (j == 0) {
|
||||
streams.err.append_format(_(L"%ls: Unknown job '%ls'\n"), L"bg");
|
||||
builtin_print_help(parser, streams, L"disown", streams.err);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
// Stopped disowned jobs must be manually signalled; explain how to do so
|
||||
if (job_is_stopped(j)) {
|
||||
killpg(j->pgid, SIGCONT);
|
||||
streams.err.append_format(
|
||||
_(L"%ls: job %d ('%ls') was stopped and has been signalled to continue.\n"),
|
||||
L"disown", j->job_id, j->command_wcstr());
|
||||
}
|
||||
|
||||
if (parser.job_remove(j)) {
|
||||
return STATUS_BUILTIN_OK;
|
||||
} else {
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/// Builtin for removing jobs from the job list
|
||||
static int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
int res = STATUS_BUILTIN_OK;
|
||||
|
||||
if (argv[1] == 0) {
|
||||
job_t *j;
|
||||
// Select last constructed job (ie first job in the job queue) that is possible to disown.
|
||||
// Stopped jobs can be disowned (they will be continued).
|
||||
// Foreground jobs can be disowned.
|
||||
// Even jobs that aren't under job control can be disowned!
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next())) {
|
||||
if (j->get_flag(JOB_CONSTRUCTED) && (!job_is_completed(j))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j) {
|
||||
res = disown_job(parser, streams, j);
|
||||
} else {
|
||||
streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), argv[0]);
|
||||
res = STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
} else {
|
||||
std::set<job_t *> jobs;
|
||||
|
||||
// If one argument is not a valid pid (i.e. integer >= 0), fail without disowning anything,
|
||||
// but still print errors for all of them.
|
||||
// Non-existent jobs aren't an error, but information about them is useful.
|
||||
// Multiple PIDs may refer to the same job; include the job only once by using a set.
|
||||
for (int i = 1; argv[i]; i++) {
|
||||
int pid = fish_wcstoi(argv[i]);
|
||||
if (errno || pid < 0) {
|
||||
streams.err.append_format(_(L"%ls: '%ls' is not a valid job specifier\n"), argv[0],
|
||||
argv[i]);
|
||||
res = STATUS_BUILTIN_ERROR;
|
||||
} else {
|
||||
if (job_t *j = parser.job_get_from_pid(pid)) {
|
||||
jobs.insert(j);
|
||||
} else {
|
||||
streams.err.append_format(_(L"%ls: Could not find job '%d'\n"), argv[0], pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res == STATUS_BUILTIN_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Disown all target jobs
|
||||
for (auto j : jobs) {
|
||||
res |= disown_job(parser, streams, j);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// This function handles both the 'continue' and the 'break' builtins that are used for loop
|
||||
/// control.
|
||||
static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
|
@ -3542,6 +3622,7 @@ static const builtin_data_t builtin_datas[] = {
|
|||
{L"continue", &builtin_break_continue,
|
||||
N_(L"Skip the rest of the current lap of the innermost loop")},
|
||||
{L"count", &builtin_count, N_(L"Count the number of arguments")},
|
||||
{L"disown", &builtin_disown, N_(L"Remove job from job list")},
|
||||
{L"echo", &builtin_echo, N_(L"Print arguments")},
|
||||
{L"else", &builtin_generic, N_(L"Evaluate block if condition is false")},
|
||||
{L"emit", &builtin_emit, N_(L"Emit an event")},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
bg: '-23' is not a valid job specifier
|
||||
fg: No suitable job: 3
|
||||
bg: Could not find job '3'
|
||||
disown: 'foo' is not a valid job specifier
|
||||
|
|
|
@ -4,4 +4,9 @@ jobs -c
|
|||
bg -23 1
|
||||
fg 3
|
||||
bg 3
|
||||
sleep 1 &
|
||||
disown
|
||||
jobs -c
|
||||
disown foo
|
||||
disown (jobs -p)
|
||||
or exit 0
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
Command
|
||||
sleep
|
||||
sleep
|
||||
Command
|
||||
sleep
|
||||
sleep
|
||||
|
|
Loading…
Reference in a new issue