Improve bg argument handling

- Error out if anything that is not a PID is given

- Otherwise background all matching existing jobs, even if not all
  PIDs exist (but print a message for the non-existing ones)

Fixes #3909.
This commit is contained in:
Fabian Homborg 2017-04-02 17:02:55 +02:00
parent b5a38ca96b
commit 3edb7d538f
5 changed files with 41 additions and 17 deletions

View file

@ -14,6 +14,7 @@
- `type` now no longer requires `which`, which means fish no longer uses it anywhere. Packagers should remove the dependency (#3912).
- Using symbolic permissions with the `umask` command now works (#738).
- Command substitutions now have access to the terminal, allowing tools like `fzf` to work in them (#1362, #3922).
- `bg`s argument parsing has been reworked. It now fails for invalid arguments but allows non-existent jobs (#3909).
---

View file

@ -11,7 +11,17 @@ bg [PID...]
The PID of the desired process is usually found by using <a href="index.html#expand-process">process expansion</a>.
When at least one of the arguments isn't a valid job specifier (i.e. PID),
`bg` will print an error without backgrounding anything.
When all arguments are valid job specifiers, bg will background all matching jobs that exist.
\subsection bg-example Example
`bg %1` will put the job with job ID 1 in the background.
`bg 123 456 789` will background 123, 456 and 789.
If only 123 and 789 exist, it will still background them and print an error about 456.
`bg 123 banana` or `bg banana 123` will complain that "banana" is not a valid job specifier.

View file

@ -2988,11 +2988,8 @@ static int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
/// Helper function for builtin_bg().
static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j, const wchar_t *name) {
if (j == 0) {
streams.err.append_format(_(L"%ls: Unknown job '%ls'\n"), L"bg", name);
builtin_print_help(parser, streams, L"bg", streams.err);
return STATUS_BUILTIN_ERROR;
} else if (!j->get_flag(JOB_CONTROL)) {
assert(j != NULL);
if (!j->get_flag(JOB_CONTROL)) {
streams.err.append_format(
_(L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n"),
L"bg", j->job_id, j->command_wcstr());
@ -3028,16 +3025,30 @@ static int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
res = send_to_bg(parser, streams, j, _(L"(default)"));
}
} else {
int i;
int pid;
std::vector<int> pids;
for (i = 1; argv[i]; i++) {
pid = fish_wcstoi(argv[i]);
if (errno || pid < 0 || !job_get_from_pid(pid)) {
streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), argv[0], argv[i]);
return STATUS_BUILTIN_ERROR;
// If one argument is not a valid pid (i.e. integer >= 0), fail without backgrounding anything,
// but still print errors for all of them.
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;
}
pids.push_back(pid);
}
if (res == STATUS_BUILTIN_ERROR) {
return res;
}
// Background all existing jobs that match the pids.
// Non-existent jobs aren't an error, but information about them is useful.
for (auto p : pids) {
if (job_t* j = job_get_from_pid(p)) {
res |= send_to_bg(parser, streams, j, *argv);
} else {
streams.err.append_format(_(L"%ls: Could not find job '%d'\n"), argv[0], p);
}
res |= send_to_bg(parser, streams, job_get_from_pid(pid), *argv);
}
}

View file

@ -1,2 +1,3 @@
bg: '3' is not a job
bg: '-23' is not a valid job specifier
fg: No suitable job: 3
bg: Could not find job '3'

View file

@ -1,6 +1,7 @@
sleep 1 &
sleep 1 &
sleep 5 &
sleep 5 &
jobs -c
bg 3
bg -23 1
fg 3
bg 3
or exit 0