mirror of
https://git.savannah.gnu.org/git/parallel.git
synced 2024-11-25 23:47:53 +00:00
parcat: Initial version.
This commit is contained in:
parent
063b64e0c9
commit
196afa553b
|
@ -1,4 +1,4 @@
|
||||||
bin_SCRIPTS = parallel sql niceload \
|
bin_SCRIPTS = parallel sql niceload parcat \
|
||||||
env_parallel env_parallel.bash env_parallel.zsh env_parallel.fish \
|
env_parallel env_parallel.bash env_parallel.zsh env_parallel.fish \
|
||||||
env_parallel.ksh env_parallel.pdksh env_parallel.csh env_parallel.tcsh
|
env_parallel.ksh env_parallel.pdksh env_parallel.csh env_parallel.tcsh
|
||||||
|
|
||||||
|
@ -8,13 +8,13 @@ install-exec-hook:
|
||||||
|
|
||||||
if DOCUMENTATION
|
if DOCUMENTATION
|
||||||
man_MANS = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
man_MANS = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
||||||
parallel_tutorial.7 parallel_design.7
|
parallel_tutorial.7 parallel_design.7 parcat.1
|
||||||
doc_DATA = parallel.html env_parallel.html sem.html sql.html niceload.html \
|
doc_DATA = parallel.html env_parallel.html sem.html sql.html niceload.html \
|
||||||
parallel_tutorial.html parallel_design.html \
|
parallel_tutorial.html parallel_design.html parcat.html \
|
||||||
parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
||||||
parallel_tutorial.texi parallel_design.texi \
|
parallel_tutorial.texi parallel_design.texi parcat.texi \
|
||||||
parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
||||||
parallel_tutorial.pdf parallel_design.pdf
|
parallel_tutorial.pdf parallel_design.pdf parcat.pdf
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Build documentation file if the tool to build exists.
|
# Build documentation file if the tool to build exists.
|
||||||
|
@ -61,6 +61,12 @@ niceload.1: niceload.pod
|
||||||
&& mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \
|
&& mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \
|
||||||
|| echo "Warning: pod2man not found. Using old niceload.1"
|
|| echo "Warning: pod2man not found. Using old niceload.1"
|
||||||
|
|
||||||
|
parcat.1: parcat
|
||||||
|
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||||
|
--section=1 $(srcdir)/parcat > $(srcdir)/parcat.1n \
|
||||||
|
&& mv $(srcdir)/parcat.1n $(srcdir)/parcat.1 \
|
||||||
|
|| echo "Warning: pod2man not found. Using old parcat.1"
|
||||||
|
|
||||||
parallel.html: parallel.pod
|
parallel.html: parallel.pod
|
||||||
pod2html --title "GNU Parallel" $(srcdir)/parallel.pod > $(srcdir)/parallel.htmln \
|
pod2html --title "GNU Parallel" $(srcdir)/parallel.pod > $(srcdir)/parallel.htmln \
|
||||||
&& mv $(srcdir)/parallel.htmln $(srcdir)/parallel.html \
|
&& mv $(srcdir)/parallel.htmln $(srcdir)/parallel.html \
|
||||||
|
@ -109,6 +115,13 @@ niceload.html: niceload.pod sql.html
|
||||||
|| echo "Warning: pod2html not found. Using old niceload.html"
|
|| echo "Warning: pod2html not found. Using old niceload.html"
|
||||||
rm -f $(srcdir)/pod2htm*
|
rm -f $(srcdir)/pod2htm*
|
||||||
|
|
||||||
|
# Depending on niceload.html to avoid stupid pod2html race condition
|
||||||
|
parcat.html: parcat niceload.html
|
||||||
|
pod2html --title "GNU parcat" $(srcdir)/parcat > $(srcdir)/parcat.htmln \
|
||||||
|
&& mv $(srcdir)/parcat.htmln $(srcdir)/parcat.html \
|
||||||
|
|| echo "Warning: pod2html not found. Using old parcat.html"
|
||||||
|
rm -f $(srcdir)/pod2htm*
|
||||||
|
|
||||||
parallel.texi: parallel.pod
|
parallel.texi: parallel.pod
|
||||||
pod2texi --output=$(srcdir)/parallel.texi $(srcdir)/parallel.pod \
|
pod2texi --output=$(srcdir)/parallel.texi $(srcdir)/parallel.pod \
|
||||||
|| echo "Warning: pod2texi not found. Using old parallel.texi"
|
|| echo "Warning: pod2texi not found. Using old parallel.texi"
|
||||||
|
@ -137,6 +150,10 @@ niceload.texi: niceload.pod
|
||||||
pod2texi --output=$(srcdir)/niceload.texi $(srcdir)/niceload.pod \
|
pod2texi --output=$(srcdir)/niceload.texi $(srcdir)/niceload.pod \
|
||||||
|| echo "Warning: pod2texi not found. Using old niceload.texi"
|
|| echo "Warning: pod2texi not found. Using old niceload.texi"
|
||||||
|
|
||||||
|
parcat.texi: parcat
|
||||||
|
pod2texi --output=$(srcdir)/parcat.texi $(srcdir)/parcat \
|
||||||
|
|| echo "Warning: pod2texi not found. Using old parcat.texi"
|
||||||
|
|
||||||
parallel.pdf: parallel.pod
|
parallel.pdf: parallel.pod
|
||||||
pod2pdf --output-file $(srcdir)/parallel.pdf $(srcdir)/parallel.pod --title "GNU Parallel" \
|
pod2pdf --output-file $(srcdir)/parallel.pdf $(srcdir)/parallel.pod --title "GNU Parallel" \
|
||||||
|| echo "Warning: pod2pdf not found. Using old parallel.pdf"
|
|| echo "Warning: pod2pdf not found. Using old parallel.pdf"
|
||||||
|
@ -165,19 +182,23 @@ niceload.pdf: niceload.pod
|
||||||
pod2pdf --output-file $(srcdir)/niceload.pdf $(srcdir)/niceload.pod --title "GNU niceload" \
|
pod2pdf --output-file $(srcdir)/niceload.pdf $(srcdir)/niceload.pod --title "GNU niceload" \
|
||||||
|| echo "Warning: pod2pdf not found. Using old niceload.pdf"
|
|| echo "Warning: pod2pdf not found. Using old niceload.pdf"
|
||||||
|
|
||||||
|
parcat.pdf: parcat
|
||||||
|
pod2pdf --output-file $(srcdir)/parcat.pdf $(srcdir)/parcat --title "GNU parcat" \
|
||||||
|
|| echo "Warning: pod2pdf not found. Using old parcat.pdf"
|
||||||
|
|
||||||
sem: parallel
|
sem: parallel
|
||||||
ln -fs parallel sem
|
ln -fs parallel sem
|
||||||
|
|
||||||
DISTCLEANFILES = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
DISTCLEANFILES = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
||||||
parallel_tutorial.7 parallel_design.7 \
|
parallel_tutorial.7 parallel_design.7 parcat.1 \
|
||||||
parallel.html env_parallel.html sem.html sql.html niceload.html \
|
parallel.html env_parallel.html sem.html sql.html niceload.html \
|
||||||
parallel_tutorial.html parallel_design.html \
|
parallel_tutorial.html parallel_design.html parcat.html \
|
||||||
parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
||||||
parallel_tutorial.texi parallel_design.texi \
|
parallel_tutorial.texi parallel_design.texi parcat.texi \
|
||||||
parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
||||||
parallel_tutorial.pdf parallel_design.pdf
|
parallel_tutorial.pdf parallel_design.pdf parcat.pdf
|
||||||
|
|
||||||
EXTRA_DIST = parallel sem sql niceload env_parallel \
|
EXTRA_DIST = parallel sem sql niceload parcat env_parallel \
|
||||||
env_parallel.bash env_parallel.zsh env_parallel.fish env_parallel.ksh \
|
env_parallel.bash env_parallel.zsh env_parallel.fish env_parallel.ksh \
|
||||||
env_parallel.pdksh env_parallel.csh env_parallel.tcsh \
|
env_parallel.pdksh env_parallel.csh env_parallel.tcsh \
|
||||||
sem.pod parallel.pod env_parallel.pod niceload.pod parallel_tutorial.pod \
|
sem.pod parallel.pod env_parallel.pod niceload.pod parallel_tutorial.pod \
|
||||||
|
|
|
@ -229,30 +229,30 @@ target_alias = @target_alias@
|
||||||
top_build_prefix = @top_build_prefix@
|
top_build_prefix = @top_build_prefix@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
bin_SCRIPTS = parallel sql niceload \
|
bin_SCRIPTS = parallel sql niceload parcat \
|
||||||
env_parallel env_parallel.bash env_parallel.zsh env_parallel.fish \
|
env_parallel env_parallel.bash env_parallel.zsh env_parallel.fish \
|
||||||
env_parallel.ksh env_parallel.pdksh env_parallel.csh env_parallel.tcsh
|
env_parallel.ksh env_parallel.pdksh env_parallel.csh env_parallel.tcsh
|
||||||
|
|
||||||
@DOCUMENTATION_TRUE@man_MANS = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
@DOCUMENTATION_TRUE@man_MANS = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
||||||
@DOCUMENTATION_TRUE@ parallel_tutorial.7 parallel_design.7
|
@DOCUMENTATION_TRUE@ parallel_tutorial.7 parallel_design.7 parcat.1
|
||||||
|
|
||||||
@DOCUMENTATION_TRUE@doc_DATA = parallel.html env_parallel.html sem.html sql.html niceload.html \
|
@DOCUMENTATION_TRUE@doc_DATA = parallel.html env_parallel.html sem.html sql.html niceload.html \
|
||||||
@DOCUMENTATION_TRUE@ parallel_tutorial.html parallel_design.html \
|
@DOCUMENTATION_TRUE@ parallel_tutorial.html parallel_design.html parcat.html \
|
||||||
@DOCUMENTATION_TRUE@ parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
@DOCUMENTATION_TRUE@ parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
||||||
@DOCUMENTATION_TRUE@ parallel_tutorial.texi parallel_design.texi \
|
@DOCUMENTATION_TRUE@ parallel_tutorial.texi parallel_design.texi parcat.texi \
|
||||||
@DOCUMENTATION_TRUE@ parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
@DOCUMENTATION_TRUE@ parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
||||||
@DOCUMENTATION_TRUE@ parallel_tutorial.pdf parallel_design.pdf
|
@DOCUMENTATION_TRUE@ parallel_tutorial.pdf parallel_design.pdf parcat.pdf
|
||||||
|
|
||||||
DISTCLEANFILES = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
DISTCLEANFILES = parallel.1 env_parallel.1 sem.1 sql.1 niceload.1 \
|
||||||
parallel_tutorial.7 parallel_design.7 \
|
parallel_tutorial.7 parallel_design.7 parcat.1 \
|
||||||
parallel.html env_parallel.html sem.html sql.html niceload.html \
|
parallel.html env_parallel.html sem.html sql.html niceload.html \
|
||||||
parallel_tutorial.html parallel_design.html \
|
parallel_tutorial.html parallel_design.html parcat.html \
|
||||||
parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
parallel.texi env_parallel.texi sem.texi sql.texi niceload.texi \
|
||||||
parallel_tutorial.texi parallel_design.texi \
|
parallel_tutorial.texi parallel_design.texi parcat.texi \
|
||||||
parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
parallel.pdf env_parallel.pdf sem.pdf sql.pdf niceload.pdf \
|
||||||
parallel_tutorial.pdf parallel_design.pdf
|
parallel_tutorial.pdf parallel_design.pdf parcat.pdf
|
||||||
|
|
||||||
EXTRA_DIST = parallel sem sql niceload env_parallel \
|
EXTRA_DIST = parallel sem sql niceload parcat env_parallel \
|
||||||
env_parallel.bash env_parallel.zsh env_parallel.fish env_parallel.ksh \
|
env_parallel.bash env_parallel.zsh env_parallel.fish env_parallel.ksh \
|
||||||
env_parallel.pdksh env_parallel.csh env_parallel.tcsh \
|
env_parallel.pdksh env_parallel.csh env_parallel.tcsh \
|
||||||
sem.pod parallel.pod env_parallel.pod niceload.pod parallel_tutorial.pod \
|
sem.pod parallel.pod env_parallel.pod niceload.pod parallel_tutorial.pod \
|
||||||
|
@ -644,6 +644,12 @@ niceload.1: niceload.pod
|
||||||
&& mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \
|
&& mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \
|
||||||
|| echo "Warning: pod2man not found. Using old niceload.1"
|
|| echo "Warning: pod2man not found. Using old niceload.1"
|
||||||
|
|
||||||
|
parcat.1: parcat
|
||||||
|
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||||
|
--section=1 $(srcdir)/parcat > $(srcdir)/parcat.1n \
|
||||||
|
&& mv $(srcdir)/parcat.1n $(srcdir)/parcat.1 \
|
||||||
|
|| echo "Warning: pod2man not found. Using old parcat.1"
|
||||||
|
|
||||||
parallel.html: parallel.pod
|
parallel.html: parallel.pod
|
||||||
pod2html --title "GNU Parallel" $(srcdir)/parallel.pod > $(srcdir)/parallel.htmln \
|
pod2html --title "GNU Parallel" $(srcdir)/parallel.pod > $(srcdir)/parallel.htmln \
|
||||||
&& mv $(srcdir)/parallel.htmln $(srcdir)/parallel.html \
|
&& mv $(srcdir)/parallel.htmln $(srcdir)/parallel.html \
|
||||||
|
@ -692,6 +698,13 @@ niceload.html: niceload.pod sql.html
|
||||||
|| echo "Warning: pod2html not found. Using old niceload.html"
|
|| echo "Warning: pod2html not found. Using old niceload.html"
|
||||||
rm -f $(srcdir)/pod2htm*
|
rm -f $(srcdir)/pod2htm*
|
||||||
|
|
||||||
|
# Depending on niceload.html to avoid stupid pod2html race condition
|
||||||
|
parcat.html: parcat niceload.html
|
||||||
|
pod2html --title "GNU parcat" $(srcdir)/parcat > $(srcdir)/parcat.htmln \
|
||||||
|
&& mv $(srcdir)/parcat.htmln $(srcdir)/parcat.html \
|
||||||
|
|| echo "Warning: pod2html not found. Using old parcat.html"
|
||||||
|
rm -f $(srcdir)/pod2htm*
|
||||||
|
|
||||||
parallel.texi: parallel.pod
|
parallel.texi: parallel.pod
|
||||||
pod2texi --output=$(srcdir)/parallel.texi $(srcdir)/parallel.pod \
|
pod2texi --output=$(srcdir)/parallel.texi $(srcdir)/parallel.pod \
|
||||||
|| echo "Warning: pod2texi not found. Using old parallel.texi"
|
|| echo "Warning: pod2texi not found. Using old parallel.texi"
|
||||||
|
@ -720,6 +733,10 @@ niceload.texi: niceload.pod
|
||||||
pod2texi --output=$(srcdir)/niceload.texi $(srcdir)/niceload.pod \
|
pod2texi --output=$(srcdir)/niceload.texi $(srcdir)/niceload.pod \
|
||||||
|| echo "Warning: pod2texi not found. Using old niceload.texi"
|
|| echo "Warning: pod2texi not found. Using old niceload.texi"
|
||||||
|
|
||||||
|
parcat.texi: parcat
|
||||||
|
pod2texi --output=$(srcdir)/parcat.texi $(srcdir)/parcat \
|
||||||
|
|| echo "Warning: pod2texi not found. Using old parcat.texi"
|
||||||
|
|
||||||
parallel.pdf: parallel.pod
|
parallel.pdf: parallel.pod
|
||||||
pod2pdf --output-file $(srcdir)/parallel.pdf $(srcdir)/parallel.pod --title "GNU Parallel" \
|
pod2pdf --output-file $(srcdir)/parallel.pdf $(srcdir)/parallel.pod --title "GNU Parallel" \
|
||||||
|| echo "Warning: pod2pdf not found. Using old parallel.pdf"
|
|| echo "Warning: pod2pdf not found. Using old parallel.pdf"
|
||||||
|
@ -748,6 +765,10 @@ niceload.pdf: niceload.pod
|
||||||
pod2pdf --output-file $(srcdir)/niceload.pdf $(srcdir)/niceload.pod --title "GNU niceload" \
|
pod2pdf --output-file $(srcdir)/niceload.pdf $(srcdir)/niceload.pod --title "GNU niceload" \
|
||||||
|| echo "Warning: pod2pdf not found. Using old niceload.pdf"
|
|| echo "Warning: pod2pdf not found. Using old niceload.pdf"
|
||||||
|
|
||||||
|
parcat.pdf: parcat
|
||||||
|
pod2pdf --output-file $(srcdir)/parcat.pdf $(srcdir)/parcat --title "GNU parcat" \
|
||||||
|
|| echo "Warning: pod2pdf not found. Using old parcat.pdf"
|
||||||
|
|
||||||
sem: parallel
|
sem: parallel
|
||||||
ln -fs parallel sem
|
ln -fs parallel sem
|
||||||
|
|
||||||
|
|
|
@ -86,9 +86,7 @@ B<Bash aliases>: Use B<env_parallel>.
|
||||||
|
|
||||||
B<Ksh functions and aliases>: Use B<env_parallel>.
|
B<Ksh functions and aliases>: Use B<env_parallel>.
|
||||||
|
|
||||||
B<Zsh functions>: Use B<env_parallel>.
|
B<Zsh functions and aliases>: Use B<env_parallel>.
|
||||||
|
|
||||||
B<Zsh aliases>: No solution.
|
|
||||||
|
|
||||||
B<Fish functions and aliases>: Use B<env_parallel>.
|
B<Fish functions and aliases>: Use B<env_parallel>.
|
||||||
|
|
||||||
|
@ -96,7 +94,6 @@ B<Ksh functions and aliases>: Use B<env_parallel>.
|
||||||
|
|
||||||
B<Pdksh functions and aliases>: Use B<env_parallel>.
|
B<Pdksh functions and aliases>: Use B<env_parallel>.
|
||||||
|
|
||||||
|
|
||||||
The command cannot contain the character \257 (macron: ¯).
|
The command cannot contain the character \257 (macron: ¯).
|
||||||
|
|
||||||
=item B<{}>
|
=item B<{}>
|
||||||
|
@ -254,7 +251,8 @@ Replace with calculated I<perl expression>. B<$_> will contain the
|
||||||
same as B<{}>. After evaluating I<perl expression> B<$_> will be used
|
same as B<{}>. After evaluating I<perl expression> B<$_> will be used
|
||||||
as the value. It is recommended to only change $_ but you have full
|
as the value. It is recommended to only change $_ but you have full
|
||||||
access to all of GNU B<parallel>'s internal functions and data
|
access to all of GNU B<parallel>'s internal functions and data
|
||||||
structures. A few convenience functions have been made:
|
structures. A few convenience functions and data structures have been
|
||||||
|
made:
|
||||||
|
|
||||||
=over 15
|
=over 15
|
||||||
|
|
||||||
|
@ -274,6 +272,10 @@ slot number of job
|
||||||
|
|
||||||
sequence number of job
|
sequence number of job
|
||||||
|
|
||||||
|
=item Z<> B<@arg>
|
||||||
|
|
||||||
|
the arguments
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -4805,19 +4807,19 @@ lacks many functions. All of these fail:
|
||||||
|
|
||||||
# -q to protect quoted $ and space
|
# -q to protect quoted $ and space
|
||||||
parallel -q perl -e '$a=shift; print "$a"x10000000' ::: a b c
|
parallel -q perl -e '$a=shift; print "$a"x10000000' ::: a b c
|
||||||
# Argument is command
|
|
||||||
parallel {} 10 ::: echo seq
|
|
||||||
# Generation of combination of inputs
|
# Generation of combination of inputs
|
||||||
parallel echo {1} {2} ::: red green blue ::: S M L XL XXL
|
parallel echo {1} {2} ::: red green blue ::: S M L XL XXL
|
||||||
# Composed commands
|
|
||||||
parallel echo {} '|' wc ::: a
|
|
||||||
# Output is mixed
|
|
||||||
parallel (-q) perl -e 'print"{}"x10000000' ::: a b c |
|
|
||||||
perl -pe '$_=join "\n",split //, $_' | uniq -c
|
|
||||||
# Show what would be executed
|
# Show what would be executed
|
||||||
parallel --dry-run echo ::: a
|
parallel --dry-run echo ::: a
|
||||||
|
# Run different shell dialects
|
||||||
|
zsh -c 'parallel echo \={} ::: zsh && true'
|
||||||
|
csh -c 'parallel echo \$\{\} ::: shell && true'
|
||||||
|
bash -c 'parallel echo \$\({}\) ::: pwd && true'
|
||||||
|
|
||||||
Rust parallel has no remote facilities.
|
Rust parallel lacks B<::::>, B<--pipe>, and has no remote facilities.
|
||||||
|
|
||||||
|
Rust parallel buffers in RAM like gargs. This can cause
|
||||||
|
death-by-swapping. See B<man parallel_design>.
|
||||||
|
|
||||||
|
|
||||||
=head2 DIFFERENCES BETWEEN ClusterSSH AND GNU Parallel
|
=head2 DIFFERENCES BETWEEN ClusterSSH AND GNU Parallel
|
||||||
|
|
|
@ -904,6 +904,31 @@ Output:
|
||||||
pre-A-post
|
pre-A-post
|
||||||
|
|
||||||
|
|
||||||
|
=head2 Respecting the shell
|
||||||
|
|
||||||
|
This tutorial uses Bash as the shell. GNU B<parallel> respects which
|
||||||
|
shell you are using, so in B<zsh> you can do:
|
||||||
|
|
||||||
|
parallel echo \={} ::: zsh bash ls
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
/usr/bin/zsh
|
||||||
|
/bin/bash
|
||||||
|
/bin/ls
|
||||||
|
|
||||||
|
In B<csh> you can do:
|
||||||
|
|
||||||
|
parallel 'set a="{}"; if( { test -d "$a" } ) echo "$a is a dir"' ::: *
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
[somedir] is a dir
|
||||||
|
|
||||||
|
This also becomes useful if you use GNU B<parallel> in a shell script:
|
||||||
|
GNU B<parallel> will use the same shell as the shell script.
|
||||||
|
|
||||||
|
|
||||||
=head1 Controlling the output
|
=head1 Controlling the output
|
||||||
|
|
||||||
The output can prefixed with the argument:
|
The output can prefixed with the argument:
|
||||||
|
|
303
src/parcat
Normal file
303
src/parcat
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
parcat - cat files or fifos in parallel
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
B<parcat> file(s)
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
GNU B<parcat> reads files or fifos in parallel. It writes full lines
|
||||||
|
so there will be no problem with mixed-half-lines which you risk if
|
||||||
|
you use:
|
||||||
|
|
||||||
|
(cat file1 & cat file2 &) | ...
|
||||||
|
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
=head2 Do be done
|
||||||
|
|
||||||
|
mkfifo slot-{1..5}-digit-{0..9}
|
||||||
|
parallel -j5 'seq 100000 | grep {} > slot-{%}-digit-{}' ::: {0..9} &
|
||||||
|
parallel parcat slot-{1..5}-digit-{} '>' digit-{} ::: {0..9}
|
||||||
|
|
||||||
|
=head1 REPORTING BUGS
|
||||||
|
|
||||||
|
GNU B<parcat> is part of GNU B<parallel>. Report bugs to <bug-parallel@gnu.org>.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
When using GNU B<sql> for a publication please cite:
|
||||||
|
|
||||||
|
O. Tange (2011): GNU SQL - A Command Line Tool for Accessing Different
|
||||||
|
Databases Using DBURLs, ;login: The USENIX Magazine, April 2011:29-32.
|
||||||
|
|
||||||
|
Copyright (C) 2008,2009,2010 Ole Tange http://ole.tange.dk
|
||||||
|
|
||||||
|
Copyright (C) 2010,2011 Ole Tange, http://ole.tange.dk and Free
|
||||||
|
Software Foundation, Inc.
|
||||||
|
|
||||||
|
=head1 LICENSE
|
||||||
|
|
||||||
|
Copyright (C) 2007,2008,2009,2010,2011 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
at your option any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
=head2 Documentation license I
|
||||||
|
|
||||||
|
Permission is granted to copy, distribute and/or modify this documentation
|
||||||
|
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||||
|
any later version published by the Free Software Foundation; with no
|
||||||
|
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||||
|
Texts. A copy of the license is included in the file fdl.txt.
|
||||||
|
|
||||||
|
=head2 Documentation license II
|
||||||
|
|
||||||
|
You are free:
|
||||||
|
|
||||||
|
=over 9
|
||||||
|
|
||||||
|
=item B<to Share>
|
||||||
|
|
||||||
|
to copy, distribute and transmit the work
|
||||||
|
|
||||||
|
=item B<to Remix>
|
||||||
|
|
||||||
|
to adapt the work
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
Under the following conditions:
|
||||||
|
|
||||||
|
=over 9
|
||||||
|
|
||||||
|
=item B<Attribution>
|
||||||
|
|
||||||
|
You must attribute the work in the manner specified by the author or
|
||||||
|
licensor (but not in any way that suggests that they endorse you or
|
||||||
|
your use of the work).
|
||||||
|
|
||||||
|
=item B<Share Alike>
|
||||||
|
|
||||||
|
If you alter, transform, or build upon this work, you may distribute
|
||||||
|
the resulting work only under the same, similar or a compatible
|
||||||
|
license.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
With the understanding that:
|
||||||
|
|
||||||
|
=over 9
|
||||||
|
|
||||||
|
=item B<Waiver>
|
||||||
|
|
||||||
|
Any of the above conditions can be waived if you get permission from
|
||||||
|
the copyright holder.
|
||||||
|
|
||||||
|
=item B<Public Domain>
|
||||||
|
|
||||||
|
Where the work or any of its elements is in the public domain under
|
||||||
|
applicable law, that status is in no way affected by the license.
|
||||||
|
|
||||||
|
=item B<Other Rights>
|
||||||
|
|
||||||
|
In no way are any of the following rights affected by the license:
|
||||||
|
|
||||||
|
=over 9
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Your fair dealing or fair use rights, or other applicable
|
||||||
|
copyright exceptions and limitations;
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
The author's moral rights;
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Rights other persons may have either in the work itself or in
|
||||||
|
how the work is used, such as publicity or privacy rights.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=item B<Notice>
|
||||||
|
|
||||||
|
For any reuse or distribution, you must make clear to others the
|
||||||
|
license terms of this work.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
A copy of the full license is included in the file as cc-by-sa.txt.
|
||||||
|
|
||||||
|
=head1 DEPENDENCIES
|
||||||
|
|
||||||
|
GNU B<parcat> uses Perl.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
B<cat>(1), B<parallel>(1)
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
|
||||||
|
use Symbol qw(gensym);
|
||||||
|
use IPC::Open3;
|
||||||
|
use POSIX qw(:errno_h);
|
||||||
|
use IO::Select;
|
||||||
|
use strict;
|
||||||
|
use threads;
|
||||||
|
use threads::shared;
|
||||||
|
use Thread::Queue;
|
||||||
|
|
||||||
|
|
||||||
|
my $opened :shared;
|
||||||
|
my $q = Thread::Queue->new();
|
||||||
|
my $okq = Thread::Queue->new();
|
||||||
|
my @producers;
|
||||||
|
|
||||||
|
if(not @ARGV) {
|
||||||
|
print "Usage:\n";
|
||||||
|
print " parcat file(s)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (@ARGV) {
|
||||||
|
push @producers, threads->create('producer', $_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub producer {
|
||||||
|
# Open a file/fifo, set non blocking, enqueue fileno of the file handle
|
||||||
|
my $file = shift;
|
||||||
|
open(my $fh, "<", $file) || do {
|
||||||
|
print STDERR "parcat: Cannot open $file\n";
|
||||||
|
exit(1);
|
||||||
|
};
|
||||||
|
set_fh_non_blocking($fh);
|
||||||
|
$q->enqueue(fileno($fh));
|
||||||
|
$opened++;
|
||||||
|
# Get an OK that the $fh is opened and we can release the $fh
|
||||||
|
while(1) {
|
||||||
|
my $ok = $okq->dequeue();
|
||||||
|
if($ok == fileno($fh)) { last; }
|
||||||
|
# Not ours - very unlikely to happen
|
||||||
|
$okq->enqueue($ok);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $s = IO::Select->new();
|
||||||
|
my %fhr;
|
||||||
|
my %buffer;
|
||||||
|
|
||||||
|
sub add_file {
|
||||||
|
my $fd = shift;
|
||||||
|
open(my $fh, "<&=", $fd) || die;
|
||||||
|
$s->add($fh);
|
||||||
|
$fhr{$fh}++;
|
||||||
|
# Tell the producer now opened here and can be released
|
||||||
|
$okq->enqueue($fd);
|
||||||
|
# Initialize the buffer
|
||||||
|
@{$buffer{$fh}} = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub add_files {
|
||||||
|
# Non-blocking dequeue
|
||||||
|
while(defined(my $fd = $q->dequeue_nb())) {
|
||||||
|
add_file($fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub add_files_block {
|
||||||
|
# Blocking dequeue
|
||||||
|
my $fd = $q->dequeue();
|
||||||
|
add_file($fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my $fd;
|
||||||
|
my (@ready,$file,$rv,$buf);
|
||||||
|
do {
|
||||||
|
# Wait until at least one file is opened
|
||||||
|
add_files_block();
|
||||||
|
while($q->pending or keys %fhr) {
|
||||||
|
add_files();
|
||||||
|
while(keys %fhr) {
|
||||||
|
@ready = $s->can_read(0.01);
|
||||||
|
if(not @ready) {
|
||||||
|
add_files();
|
||||||
|
}
|
||||||
|
for $file (@ready) {
|
||||||
|
$rv = sysread($file, $buf, 65536);
|
||||||
|
if (!$rv) {
|
||||||
|
if($! == EAGAIN) {
|
||||||
|
# Would block: Nothing read
|
||||||
|
next;
|
||||||
|
} else {
|
||||||
|
# This file is done
|
||||||
|
$s->remove($file);
|
||||||
|
delete $fhr{$file};
|
||||||
|
print @{$buffer{$file}};
|
||||||
|
delete $buffer{$file};
|
||||||
|
# Closing the $file causes it to block
|
||||||
|
# close $file;
|
||||||
|
add_files();
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find \n for full line
|
||||||
|
my $i = (rindex($buf,"\n")+1);
|
||||||
|
if($i) {
|
||||||
|
# Print full line
|
||||||
|
for(@{$buffer{$file}}, substr($buf,0,$i)) {
|
||||||
|
syswrite(STDOUT,$_);
|
||||||
|
}
|
||||||
|
# @buffer = remaining half line
|
||||||
|
@{$buffer{$file}} = (substr($buf,$i,$rv-$i));
|
||||||
|
redo;
|
||||||
|
} else {
|
||||||
|
# Something read, but not a full line
|
||||||
|
push @{$buffer{$file}}, $buf;
|
||||||
|
redo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while($opened <= $#ARGV);
|
||||||
|
|
||||||
|
|
||||||
|
for (@producers) {
|
||||||
|
$_->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_fh_non_blocking {
|
||||||
|
# Set filehandle as non-blocking
|
||||||
|
# Inputs:
|
||||||
|
# $fh = filehandle to be blocking
|
||||||
|
# Returns:
|
||||||
|
# N/A
|
||||||
|
my $fh = shift;
|
||||||
|
$Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;";
|
||||||
|
my $flags;
|
||||||
|
fcntl($fh, &F_GETFL, $flags) || die $!; # Get the current flags on the filehandle
|
||||||
|
$flags |= &O_NONBLOCK; # Add non-blocking to the flags
|
||||||
|
fcntl($fh, &F_SETFL, $flags) || die $!; # Set the flags on the filehandle
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue