parallel: Basic --completion implemented for zsh.

This commit is contained in:
Ole Tange 2022-04-01 01:23:04 +02:00
parent cfc2eed39f
commit add978635c
3 changed files with 410 additions and 168 deletions

View file

@ -1,5 +1,6 @@
People who have helped GNU Parallel different ways. People who have helped GNU Parallel different ways.
Wu Zhenyu: Code snips for --completion zsh.
Morten Rønne: Donating his old Mac for testing. Morten Rønne: Donating his old Mac for testing.
Renan Valieris: Maintaining GNU Parallel for Anaconda Cloud. Renan Valieris: Maintaining GNU Parallel for Anaconda Cloud.
Jakub Kulík: Maintaining GNU Parallel for Solaris-userland. Jakub Kulík: Maintaining GNU Parallel for Solaris-userland.

View file

@ -1554,197 +1554,425 @@ sub acquire_semaphore() {
sub __PARSE_OPTIONS__() {} sub __PARSE_OPTIONS__() {}
sub shell_completion() {
if($opt::completion eq "zsh") {
# if(shell == zsh);
zsh_competion();
} elsif($opt::completion eq "auto") {
if($Global::shell =~ m:/zsh$|^zsh$:) {
# if(shell == zsh);
zsh_competion();
} else {
::error("--completion is not implemented for '$Global::shell'.");
wait_and_exit(255);
}
} else {
::error("--completion is not implemented for '$opt::completion'.");
wait_and_exit(255);
}
}
sub zsh_competion() {
my @zsh_completion =
("compdef _comp_parallel parallel; ",
"setopt localoptions extended_glob; ",
"local -a _comp_priv_prefix; ",
"_comp_parallel() { ",
"_arguments ");
my @och = options_completion_hash();
while(@och) {
$_ = shift @och;
# Split input like:
# "joblog|jl=s[Logfile for executed jobs]:logfile:_files"
if(/^(.*?)(\[.*?])(:[^:]*)?(:.*)?$/) {
my $opt = $1;
my $desc = $2;
my $argdesc = $3;
my $func = $4;
# opt=s => opt
$opt =~ s/[:=].$//;
# {-o,--option}
my $zsh_opt = join(",",
(map { (length $_ == 1) ? "-$_" : "--$_" }
split /\|/, $opt));
if($zsh_opt =~ /,/) { $zsh_opt = "{$zsh_opt}"; }
$desc =~ s/'/'"'"'/g;
$argdesc =~ s/'/'"'"'/g;
$func =~ s/'/'"'"'/g;
push @zsh_completion, $zsh_opt."'".$desc.$argdesc.$func."' ";
}
shift @och;
}
push @zsh_completion,
q{'(-)1:command: _command_names -e' },
q{'*::arguments:{ _comp_priv_prefix=( '$words[1]' -n ${(kv)opt_args[(I)(-[ugHEP]|--(user|group|set-home|preserve-env|preserve-groups))]} ) ; _normal }'},
"};\n";
print @zsh_completion;
}
sub options_hash() { sub options_hash() {
# Returns: # Returns:
# %hash = the GetOptions config # %hash = for GetOptions
my %och = options_completion_hash();
my %oh;
my ($k,$v);
while(($k,$v) = each %och) {
$k =~ s/\[.*//;
$oh{$k} = $v;
}
return %oh;
}
sub options_completion_hash() {
# Returns:
# %hash = for GetOptions and shell completion
return return
("debug|D=s" => \$opt::D, ("debug|D=s" => \$opt::D,
"xargs" => \$opt::xargs, "xargs[Insert as many arguments as the command line length permits]"
"m" => \$opt::m, => \$opt::xargs,
"X" => \$opt::X, "m[Multiple arguments]" => \$opt::m,
"v" => \@opt::v, ("X[Insert as many arguments with context as the command line length permits]"
"sql=s" => \$opt::retired, => \$opt::X),
"sql-master|sqlmaster=s" => \$opt::sqlmaster, "v[Verbose]" => \@opt::v,
"sql-worker|sqlworker=s" => \$opt::sqlworker, "sql=s[Use --sql-master instead (obsolete)]:DBURL" => \$opt::retired,
"sql-and-worker|sqlandworker=s" => \$opt::sqlandworker, ("sql-master|sqlmaster=s".
"joblog|jl=s" => \$opt::joblog, "[Submit jobs via SQL server. DBURL must point to a table, which will contain --joblog, the values, and output]:DBURL"
"results|result|res=s" => \$opt::results, => \$opt::sqlmaster),
"resume" => \$opt::resume, ("sql-worker|sqlworker=s".
"resume-failed|resumefailed" => \$opt::resume_failed, "[Execute jobs via SQL server. Read the input sources variables from the table pointed to by DBURL.]:DBURL"
"retry-failed|retryfailed" => \$opt::retry_failed, => \$opt::sqlworker),
"silent" => \$opt::silent, ("sql-and-worker|sqlandworker=s".
"keep-order|keeporder|k" => \$opt::keeporder, "[--sql-master DBURL --sql-worker DBURL]:DBURL"
"no-keep-order|nokeeporder|nok|no-k" => \$opt::nokeeporder, => \$opt::sqlandworker),
"group" => \$opt::group, ("joblog|jl=s[Logfile for executed jobs]:logfile:_files"
=> \$opt::joblog),
("results|result|res=s[Save the output into files]:name:_files"
=> \$opt::results),
"resume[Resumes from the last unfinished job]" => \$opt::resume,
("resume-failed|resumefailed".
"[Retry all failed and resume from the last unfinished job]"
=> \$opt::resume_failed),
("retry-failed|retryfailed[Retry all failed jobs in joblog]"
=> \$opt::retry_failed),
"silent[Silent]" => \$opt::silent,
("keep-order|keeporder|k".
"[Keep sequence of output same as the order of input]"
=> \$opt::keeporder),
("no-keep-order|nokeeporder|nok|no-k".
"[Overrides an earlier --keep-order (e.g. if set in ~/.parallel/config)]"
=> \$opt::nokeeporder),
"group[Group output]" => \$opt::group,
"g" => \$opt::retired, "g" => \$opt::retired,
"ungroup|u" => \$opt::ungroup, ("ungroup|u".
"line-buffer|line-buffered|linebuffer|linebuffered|lb" "[Output is printed as soon as possible and bypasses GNU parallel internal processing]"
=> \$opt::linebuffer, => \$opt::ungroup),
"tmux" => \$opt::tmux, ("line-buffer|line-buffered|linebuffer|linebuffered|lb".
"tmux-pane|tmuxpane" => \$opt::tmuxpane, "[Buffer output on line basis]"
"null|0" => \$opt::null, => \$opt::linebuffer),
"quote|q" => \$opt::quote, ("tmux".
"[Use tmux for output. Start a tmux session and run each job in a window in that session. No other output will be produced]"
=> \$opt::tmux),
("tmux-pane|tmuxpane".
"[Use tmux for output but put output into panes in the first window. Useful if you want to monitor the progress of less than 100 concurrent jobs]"
=> \$opt::tmuxpane),
"null|0[Use NUL as delimiter]" => \$opt::null,
"quote|q[Quote command]" => \$opt::quote,
# Replacement strings # Replacement strings
"parens=s" => \$opt::parens, ("parens=s[Use parensstring instead of {==}]:parensstring"
"rpl=s" => \@opt::rpl, => \$opt::parens),
"plus" => \$opt::plus, ('rpl=s[Define replacement string]:"tag perl expression"'
"I=s" => \$opt::I, => \@opt::rpl),
"extensionreplace|er=s" => \$opt::U, "plus[Add more replacement strings]" => \$opt::plus,
("I=s".
"[Use the replacement string replace-str instead of {}]:replace-str"
=> \$opt::I),
("extensionreplace|er=s".
"[Use the replacement string replace-str instead of {.} for input line without extension]:replace-str"
=> \$opt::U),
"U=s" => \$opt::retired, "U=s" => \$opt::retired,
"basenamereplace|bnr=s" => \$opt::basenamereplace, ("basenamereplace|bnr=s".
"dirnamereplace|dnr=s" => \$opt::dirnamereplace, "[Use the replacement string replace-str instead of {/} for basename of input line]:replace-str"
"basenameextensionreplace|bner=s" => \$opt::basenameextensionreplace, => \$opt::basenamereplace),
"seqreplace=s" => \$opt::seqreplace, ("dirnamereplace|dnr=s".
"slotreplace=s" => \$opt::slotreplace, "[Use the replacement string replace-str instead of {//} for dirname of input line]:replace-str"
"jobs|j=s" => \$opt::jobs, => \$opt::dirnamereplace),
"delay=s" => \$opt::delay, ("basenameextensionreplace|bner=s".
"sshdelay=f" => \$opt::sshdelay, "[Use the replacement string replace-str instead of {/.} for basename of input line without extension]:replace-str"
"load=s" => \$opt::load, => \$opt::basenameextensionreplace),
"noswap" => \$opt::noswap, ("seqreplace=s".
"max-line-length-allowed|maxlinelengthallowed" "[Use the replacement string replace-str instead of {#} for job sequence number]:replace-str"
=> \$opt::max_line_length_allowed, => \$opt::seqreplace),
"number-of-cpus|numberofcpus" => \$opt::number_of_cpus, ("slotreplace=s".
"number-of-sockets|numberofsockets" => \$opt::number_of_sockets, "[Use the replacement string replace-str instead of {%} for job slot number]:replace-str"
"number-of-cores|numberofcores" => \$opt::number_of_cores, => \$opt::slotreplace),
"number-of-threads|numberofthreads" => \$opt::number_of_threads, ("jobs|j=s".
"use-sockets-instead-of-threads|usesocketsinsteadofthreads" "[(Add +N to/Subtract -N from/Multiply N%) the number of CPU threads or read parameter from file]:_files"
=> \$opt::use_sockets_instead_of_threads, => \$opt::jobs),
"use-cores-instead-of-threads|usecoresinsteadofthreads" ("delay=s".
=> \$opt::use_cores_instead_of_threads, "[Delay starting next job by duration]:duration" => \$opt::delay),
"use-cpus-instead-of-cores|usecpusinsteadofcores" ("ssh-delay|sshdelay=f".
=> \$opt::use_cpus_instead_of_cores, "[Delay starting next ssh by duration]:duration"
"shell-quote|shellquote|shell_quote" => \@opt::shellquote, => \$opt::sshdelay),
"nice=i" => \$opt::nice, ("load=s".
"tag" => \$opt::tag, "[Only start jobs if load is less than max-load]:max-load"
"tag-string|tagstring=s" => \$opt::tagstring, => \$opt::load),
"ctag" => \$opt::ctag, "noswap[Do not start job is computer is swapping]" => \$opt::noswap,
"ctag-string|ctagstring=s" => \$opt::ctagstring, ("max-line-length-allowed|maxlinelengthallowed".
"onall" => \$opt::onall, "[Print maximal command line length]"
"nonall" => \$opt::nonall, => \$opt::max_line_length_allowed),
"filter-hosts|filterhosts|filter-host" => \$opt::filter_hosts, ("number-of-cpus|numberofcpus".
"sshlogin|S=s" => \@opt::sshlogin, "[Print the number of physical CPU cores and exit (obsolete)]"
"sshloginfile|slf=s" => \@opt::sshloginfile, => \$opt::number_of_cpus),
"controlmaster|M" => \$opt::controlmaster, ("number-of-sockets|numberofsockets".
"ssh=s" => \$opt::ssh, "[Print the number of CPU sockets and exit]"
"transfer-file|transferfile|transfer-files|transferfiles|tf=s" => \$opt::number_of_sockets),
=> \@opt::transfer_files, ("number-of-cores|numberofcores".
"return=s" => \@opt::return, "[Print the number of physical CPU cores and exit]"
"trc=s" => \@opt::trc, => \$opt::number_of_cores),
"transfer" => \$opt::transfer, ("number-of-threads|numberofthreads".
"cleanup" => \$opt::cleanup, "[Print the number of hyperthreaded CPU cores and exit]"
"basefile|bf=s" => \@opt::basefile, => \$opt::number_of_threads),
"template|tmpl=s" => \%opt::template, ("use-sockets-instead-of-threads|usesocketsinsteadofthreads".
"[Determine how GNU Parallel counts the number of CPUs]"
=> \$opt::use_sockets_instead_of_threads),
("use-cores-instead-of-threads|usecoresinsteadofthreads".
"[Determine how GNU Parallel counts the number of CPUs]"
=> \$opt::use_cores_instead_of_threads),
("use-cpus-instead-of-cores|usecpusinsteadofcores".
"[Determine how GNU Parallel counts the number of CPUs]"
=> \$opt::use_cpus_instead_of_cores),
("shell-quote|shellquote|shell_quote".
"[Does not run the command but quotes it. Useful for making quoted composed commands for GNU parallel]"
=> \@opt::shellquote),
('nice=i[Run the command at this niceness]:niceness:($(seq -20 19))'
=> \$opt::nice),
"tag[Tag lines with arguments]" => \$opt::tag,
("tag-string|tagstring=s".
"[Tag lines with a string]:str" => \$opt::tagstring),
"ctag[Color tag]:str" => \$opt::ctag,
"ctag-string|ctagstring=s[Color tagstring]:str" => \$opt::ctagstring,
("onall[Run all the jobs on all computers given with --sshlogin]"
=> \$opt::onall),
"nonall[--onall with no arguments]" => \$opt::nonall,
("filter-hosts|filterhosts|filter-host[Remove down hosts]"
=> \$opt::filter_hosts),
('sshlogin|S=s'.
'[Distribute jobs to remote computers]'.
':[@hostgroups/][ncpus/]sshlogin[,[@hostgroups/][ncpus/]sshlogin[,...]] or @hostgroup'.
':_users') => \@opt::sshlogin,
("sshloginfile|slf=s".
"[File with sshlogins on separate lines. Lines starting with '#' are ignored.]:filename:_files"
=> \@opt::sshloginfile),
("controlmaster|M".
"[Use ssh's ControlMaster to make ssh connections faster]"
=> \$opt::controlmaster),
("ssh=s".
"[Use this command instead of ssh for remote access]:sshcommand"
=> \$opt::ssh),
("transfer-file|transferfile|transfer-files|transferfiles|tf=s".
"[Transfer filename to remote computers]:filename:_files"
=> \@opt::transfer_files),
("return=s[Transfer files from remote computers]:filename:_files"
=> \@opt::return),
("trc=s[--transfer --return filename --cleanup]:filename:_files"
=> \@opt::trc),
"transfer[Transfer files to remote computers]" => \$opt::transfer,
"cleanup[Remove transferred files]" => \$opt::cleanup,
("basefile|bf=s".
"[Transfer file to each sshlogin before first job is started]:file:_files"
=> \@opt::basefile),
("template|tmpl=s[Replace replacement strings in file and save it in repl]:file=repl:_files"
=> \%opt::template),
"B=s" => \$opt::retired, "B=s" => \$opt::retired,
"ctrl-c|ctrlc" => \$opt::retired, "ctrl-c|ctrlc" => \$opt::retired,
"no-ctrl-c|no-ctrlc|noctrlc" => \$opt::retired, "no-ctrl-c|no-ctrlc|noctrlc" => \$opt::retired,
"work-dir|workdir|wd=s" => \$opt::workdir, ("work-dir|workdir|wd=s".
"[Jobs will be run in the dir mydir. (default: the current dir for the local machine, the login dir for remote computers)]:mydir:_cd"
=> \$opt::workdir),
"W=s" => \$opt::retired, "W=s" => \$opt::retired,
"rsync-opts|rsyncopts=s" => \$opt::rsync_opts, ("rsync-opts|rsyncopts=s[Options to pass on to rsync]:options"
"tmpdir|tempdir=s" => \$opt::tmpdir, => \$opt::rsync_opts),
"use-compress-program|compress-program|". ("tmpdir|tempdir=s[Directory for temporary files]:dirname:_cd"
"usecompressprogram|compressprogram=s" => \$opt::compress_program, => \$opt::tmpdir),
"use-decompress-program|decompress-program|". ("use-compress-program|compress-program|".
"usedecompressprogram|decompressprogram=s" "usecompressprogram|compressprogram=s".
=> \$opt::decompress_program, "[Use prg for compressing temporary files]:prg:_commands"
"compress" => \$opt::compress, => \$opt::compress_program),
"tty" => \$opt::tty, ("use-decompress-program|decompress-program|".
"usedecompressprogram|decompressprogram=s".
"[Use prg for decompressing temporary files]:prg:_commands"
=> \$opt::decompress_program),
"compress[Compress temporary files]" => \$opt::compress,
"tty[Open terminal tty]" => \$opt::tty,
"T" => \$opt::retired, "T" => \$opt::retired,
"H=i" => \$opt::retired, "H=i" => \$opt::retired,
"dry-run|dryrun|dr" => \$opt::dryrun, ("dry-run|dryrun|dr".
"progress" => \$opt::progress, "[Print the job to run on stdout (standard output), but do not run the job]"
"eta" => \$opt::eta, => \$opt::dryrun),
"bar" => \$opt::bar, "progress[Show progress of computations]" => \$opt::progress,
"shuf" => \$opt::shuf, ("eta[Show the estimated number of seconds before finishing]"
"arg-sep|argsep=s" => \$opt::arg_sep, => \$opt::eta),
"arg-file-sep|argfilesep=s" => \$opt::arg_file_sep, "bar[Show progress as a progress bar]" => \$opt::bar,
"trim=s" => \$opt::trim, "shuf[Shuffle jobs]" => \$opt::shuf,
"env=s" => \@opt::env, ("arg-sep|argsep=s".
"recordenv|record-env" => \$opt::record_env, "[Use sep-str instead of ::: as separator string]:sep-str"
"session" => \$opt::session, => \$opt::arg_sep),
"plain" => \$opt::plain, ("arg-file-sep|argfilesep=s".
"profile|J=s" => \@opt::profile, "[Use sep-str instead of :::: as separator string between command and argument files]:sep-str"
=> \$opt::arg_file_sep),
("trim=s[Trim white space in input]:trim_method:(n l r lr rl)"
=> \$opt::trim),
"env=s[Copy environment variable var]:var:_vars" => \@opt::env,
"recordenv|record-env[Record environment]" => \$opt::record_env,
('session'.
'[Record names in current environment in $PARALLEL_IGNORED_NAMES and exit. Only used with env_parallel. Aliases, functions, and variables with names i]'
=> \$opt::session),
('plain[Ignore --profile, $PARALLEL, and ~/.parallel/config]'
=> \$opt::plain),
("profile|J=s".
"[Use profile profilename for options]:profilename:_files"
=> \@opt::profile),
"tollef" => \$opt::tollef, "tollef" => \$opt::tollef,
"gnu" => \$opt::gnu, "gnu[Behave like GNU parallel]" => \$opt::gnu,
"link|xapply" => \$opt::link, "link|xapply[Link input sources]" => \$opt::link,
"linkinputsource|xapplyinputsource=i" => \@opt::linkinputsource, "linkinputsource|xapplyinputsource=i" => \@opt::linkinputsource,
# Before changing these lines, please read # Before changing these lines, please read
# https://www.gnu.org/software/parallel/parallel_design.html#citation-notice # https://www.gnu.org/software/parallel/parallel_design.html#citation-notice
# https://git.savannah.gnu.org/cgit/parallel.git/tree/doc/citation-notice-faq.txt # https://git.savannah.gnu.org/cgit/parallel.git/tree/doc/citation-notice-faq.txt
# You accept to be put in a public hall of shame by removing # You accept to be put in a public hall of shame by removing
# these lines. # these lines.
"bibtex|citation" => \$opt::citation, ("bibtex|citation".
"[Print the citation notice and BibTeX entry for GNU parallel, silence citation notice for all future runs, and exit. It will not run any commands]"
=> \$opt::citation),
"will-cite|willcite|nn|nonotice|no-notice" => \$opt::willcite, "will-cite|willcite|nn|nonotice|no-notice" => \$opt::willcite,
# Termination and retries # Termination and retries
"halt-on-error|haltonerror|halt=s" => \$opt::halt, ('halt-on-error|haltonerror|halt=s'.
"limit=s" => \$opt::limit, '[When should GNU parallel terminate]:when:((now\:"kill all running jobs and halt immediately" soon\:"wait for all running jobs to complete, start no new jobs"))'
"memfree=s" => \$opt::memfree, => \$opt::halt),
"memsuspend=s" => \$opt::memsuspend, 'limit=s[Dynamic job limit]:"command args"' => \$opt::limit,
"retries=s" => \$opt::retries, ("memfree=s".
"timeout=s" => \$opt::timeout, "[Minimum memory free when starting another job]:size"
"term-seq|termseq=s" => \$opt::termseq, => \$opt::memfree),
("memsuspend=s".
"[Suspend jobs when there is less memory available]:size"
=> \$opt::memsuspend),
"retries=s[Try failing jobs n times]:n" => \$opt::retries,
("timeout=s".
"[Time out for command. If the command runs for longer than duration seconds it will get killed as per --term-seq]:duration"
=> \$opt::timeout),
("term-seq|termseq=s".
"[Termination sequence]:sequence" => \$opt::termseq),
# xargs-compatibility - implemented, man, testsuite # xargs-compatibility - implemented, man, testsuite
"max-procs|maxprocs|P=s" => \$opt::jobs, ("max-procs|maxprocs|P=s".
"delimiter|d=s" => \$opt::d, "[Add N to/Subtract N from/Multiply N% with/ the number of CPU threads or read parameter from file]:+N/-N/N%/N/procfile:_files"
"max-chars|maxchars|s=s" => \$opt::max_chars, => \$opt::jobs),
"arg-file|arg-file|a=s" => \@opt::a, ("delimiter|d=s[Input items are terminated by delim]:delim"
"no-run-if-empty|norunifempty|r" => \$opt::r, => \$opt::d),
"replace|i:s" => \$opt::i, ("max-chars|maxchars|s=s[Limit length of command]:max-chars"
=> \$opt::max_chars),
("arg-file|argfile|a=s".
"[Use input-file as input source]:input-file:_files" => \@opt::a),
"no-run-if-empty|norunifempty|r[Do not run empty input]" => \$opt::r,
("replace|i:s".
"[This option is deprecated; use -I instead]:replace-str"
=> \$opt::i),
"E=s" => \$opt::eof, "E=s" => \$opt::eof,
"eof|e:s" => \$opt::eof, ("eof|e:s[Set the end of file string to eof-str]:eof-str"
"max-args|maxargs|n=s" => \$opt::max_args, => \$opt::eof),
"max-replace-args|maxreplaceargs|N=s" ("max-args|maxargs|n=s".
=> \$opt::max_replace_args, "[Use at most max-args arguments per command line]:max-args"
"col-sep|colsep|C=s" => \$opt::colsep, => \$opt::max_args),
"csv"=> \$opt::csv, ("max-replace-args|maxreplaceargs|N=s".
"help|h" => \$opt::help, "[Use at most max-args arguments per command line]:max-args"
"L=s" => \$opt::L, => \$opt::max_replace_args),
"max-lines|maxlines|l:f" => \$opt::max_lines, "col-sep|colsep|C=s[Column separator]:regexp" => \$opt::colsep,
"interactive|p" => \$opt::interactive, "csv[Treat input as CSV-format]"=> \$opt::csv,
"verbose|t" => \$opt::verbose, ("help|h[Print a summary of the options to GNU parallel and exit]"
"version|V" => \$opt::version, => \$opt::help),
"min-version|minversion=i" => \$opt::minversion, ("L=s[When used with --pipe: Read records of recsize]:recsize"
"show-limits|showlimits" => \$opt::show_limits, => \$opt::L),
"exit|x" => \$opt::x, ("max-lines|maxlines|l:f".
"[When used with --pipe: Read records of recsize lines]:recsize"
=> \$opt::max_lines),
"interactive|p[Ask user before running a job]" => \$opt::interactive,
("verbose|t[Print the job to be run on stderr (standard error)]"
=> \$opt::verbose),
("version|V[Print the version GNU parallel and exit]"
=> \$opt::version),
('min-version|minversion=i'.
'[Print the version GNU parallel and exit]:version:($(parallel --minversion 0))'
=> \$opt::minversion),
("show-limits|showlimits".
"[Display limits given by the operating system]"
=> \$opt::show_limits),
("exit|x[Exit if the size (see the -s option) is exceeded]"
=> \$opt::x),
# Semaphore # Semaphore
"semaphore" => \$opt::semaphore, "semaphore[Work as a counting semaphore]" => \$opt::semaphore,
"semaphore-timeout|semaphoretimeout|st=s" ("semaphore-timeout|semaphoretimeout|st=s".
=> \$opt::semaphoretimeout, "[If secs > 0: If the semaphore is not released within secs seconds, take it anyway]:secs"
"semaphore-name|semaphorename|id=s" => \$opt::semaphorename, => \$opt::semaphoretimeout),
"fg" => \$opt::fg, ("semaphore-name|semaphorename|id=s".
"bg" => \$opt::bg, "[Use name as the name of the semaphore]:name"
"wait" => \$opt::wait, => \$opt::semaphorename),
"fg[Run command in foreground]" => \$opt::fg,
"bg[Run command in background]" => \$opt::bg,
"wait[Wait for all commands to complete]" => \$opt::wait,
# Shebang #!/usr/bin/parallel --shebang # Shebang #!/usr/bin/parallel --shebang
"shebang|hashbang" => \$opt::shebang, ("shebang|hashbang".
"internal-pipe-means-argfiles|internalpipemeansargfiles" "[GNU parallel can be called as a shebang (#!) command as the first line of a script. The content of the file will be treated as inputsource]"
=> \$opt::internal_pipe_means_argfiles, => \$opt::shebang),
("internal-pipe-means-argfiles|internalpipemeansargfiles"
=> \$opt::internal_pipe_means_argfiles),
"Y" => \$opt::retired, "Y" => \$opt::retired,
"skip-first-line|skipfirstline" ("skip-first-line|skipfirstline".
=> \$opt::skip_first_line, "[Do not use the first line of input (used by GNU parallel itself when called with --shebang)]"
=> \$opt::skip_first_line),
"bug" => \$opt::bug, "bug" => \$opt::bug,
# --pipe # --pipe
"pipe|spreadstdin" => \$opt::pipe, ("pipe|spreadstdin".
"round-robin|roundrobin|round" => \$opt::roundrobin, "[Spread input to jobs on stdin (standard input)]" => \$opt::pipe),
("round-robin|roundrobin|round".
"[Distribute chunks of standard input in a round robin fashion]"
=> \$opt::roundrobin),
"recstart=s" => \$opt::recstart, "recstart=s" => \$opt::recstart,
"recend=s" => \$opt::recend, ("recend=s".
"regexp|regex" => \$opt::regexp, "[Split record between endstring and startstring]:endstring"
"remove-rec-sep|removerecsep|rrs" => \$opt::remove_rec_sep, => \$opt::recend),
"output-as-files|outputasfiles|files" => \$opt::files, ("regexp|regex".
"block-size|blocksize|block=s" => \$opt::blocksize, "[Use --regexp to interpret --recstart and --recend as regular expressions]"
"block-timeout|blocktimeout|bt=s" => \$opt::blocktimeout, => \$opt::regexp),
"header=s" => \$opt::header, ("remove-rec-sep|removerecsep|rrs".
"cat" => \$opt::cat, "[Remove record separator]" => \$opt::remove_rec_sep),
"fifo" => \$opt::fifo, ("output-as-files|outputasfiles|files[Save output to files]"
"pipe-part|pipepart" => \$opt::pipepart, => \$opt::files),
"tee" => \$opt::tee, ("block-size|blocksize|block=s".
"shard=s" => \$opt::shard, "[Size of block in bytes to read at a time]:size"
"bin=s" => \$opt::bin, => \$opt::blocksize),
"group-by|groupby=s" => \$opt::groupby, ("block-timeout|blocktimeout|bt=s".
"[Timeout for reading block when using --pipe]:duration"
=> \$opt::blocktimeout),
"header=s[Use regexp as header]:regexp" => \$opt::header,
"cat[Create a temporary file with content]" => \$opt::cat,
"fifo[Create a temporary fifo with content]" => \$opt::fifo,
("pipe-part|pipepart[Pipe parts of a physical file]"
=> \$opt::pipepart),
"tee[Pipe all data to all jobs]" => \$opt::tee,
("shard=s".
"[Use shardexpr as shard key and shard input to the jobs]:shardexpr"
=> \$opt::shard),
("bin=s".
"[Use binexpr as binning key and bin input to the jobs]:binexpr"
=> \$opt::bin),
"group-by|groupby=s[Group input by value]:val" => \$opt::groupby,
# #
"hgrp|hostgrp|hostgroup|hostgroups" => \$opt::hostgroups, ("hgrp|hostgrp|hostgroup|hostgroups[Enable hostgroups on arguments]"
"embed" => \$opt::embed, => \$opt::hostgroups),
"filter=s" => \@opt::filter, "embed[Embed GNU parallel in a shell script]" => \$opt::embed,
("filter=s[Only run jobs where filter is true]:filter"
=> \@opt::filter),
"parset=s" => \$opt::parset, "parset=s" => \$opt::parset,
"completion=s" => \$opt::completion,
# Parameter for testing optimal values # Parameter for testing optimal values
"test=s" => \$opt::test, "test=s" => \$opt::test,
); );
@ -1905,6 +2133,7 @@ sub parse_options(@) {
# Default: Same nice level as GNU Parallel is started at # Default: Same nice level as GNU Parallel is started at
$opt::nice ||= eval { getpriority(0,0) } || 0; $opt::nice ||= eval { getpriority(0,0) } || 0;
if(defined $opt::help) { usage(); exit(0); } if(defined $opt::help) { usage(); exit(0); }
if(defined $opt::completion) { shell_completion(); exit(0); }
if(defined $opt::embed) { embed(); exit(0); } if(defined $opt::embed) { embed(); exit(0); }
if(defined $opt::sqlandworker) { if(defined $opt::sqlandworker) {
$opt::sqlmaster = $opt::sqlworker = $opt::sqlandworker; $opt::sqlmaster = $opt::sqlworker = $opt::sqlandworker;
@ -2313,7 +2542,7 @@ sub check_invalid_option_combinations() {
sub init_globals() { sub init_globals() {
# Defaults: # Defaults:
$Global::version = 20220323; $Global::version = 20220331;
$Global::progname = 'parallel'; $Global::progname = 'parallel';
$::name = "GNU Parallel"; $::name = "GNU Parallel";
$Global::infinity = 2**31; $Global::infinity = 2**31;
@ -6119,7 +6348,6 @@ sub usleep($) {
sub make_regexp_ungreedy { sub make_regexp_ungreedy {
my $regexp = shift; my $regexp = shift;
my $class_state = 0; my $class_state = 0;
my $escape_state = 0; my $escape_state = 0;
my $found = 0; my $found = 0;

View file

@ -774,6 +774,19 @@ https://perldoc.perl.org/perlre.html
See also: B<--csv> B<{>I<n>B<}> B<--trim> B<--link> See also: B<--csv> B<{>I<n>B<}> B<--trim> B<--link>
=item B<--completion> I<shell> (alpha testing)
Generate shell completion code for interactive shells.
Supported shells: zsh.
Use I<auto> as I<shell> to automatically detect running shell.
Activate the completion code with:
zsh% eval "`parallel --completion auto`"
=item B<--compress> =item B<--compress>
Compress temporary files. Compress temporary files.