aboutsummaryrefslogtreecommitdiff
path: root/bin/x
diff options
context:
space:
mode:
Diffstat (limited to 'bin/x')
-rwxr-xr-xbin/x124
1 files changed, 124 insertions, 0 deletions
diff --git a/bin/x b/bin/x
new file mode 100755
index 0000000..42f5770
--- /dev/null
+++ b/bin/x
@@ -0,0 +1,124 @@
+#!/usr/bin/env perl
+
+use v5.34;
+use warnings;
+use feature 'signatures';
+no warnings ('experimental::signatures', 'experimental::smartmatch');
+use Getopt::Std ();
+
+sub usage($fh) {
+ print $fh <<~'EOF'
+ Usage:
+ x COMMANDS... [ '&&' / '||' / '|' ] COMMANDS...
+ x COMMANDS... [ 'AND' / 'OR' / 'PIPE' ] COMMANDS...
+ x -h
+ EOF
+}
+
+sub help($fh) {
+ print $fh <<~'EOF'
+
+ Options:
+ -h, --help show this message
+
+ COMMAND the command to be executed
+ '&&' / AND "AND" logical operator
+ '||' / OR "OR" logical operator
+ '|' / PIPE pipe operator
+
+
+ Run command chained together with operators.
+
+ NOTE: Remember to quote '&&', 'OR' and '|' operators, otherwise
+ they'll get captured by the shell and not be passed to the 'x'
+ program!
+
+
+ Examples:
+
+ Measure the time of two commands:
+
+ $ time x sleep 1 '&&' sleep 2
+ # equivalent to:
+ $ time sh -c 'sleep 1 && sleep 2'
+
+
+ Notify when either of the commands finish:
+
+ $ boop x cmd-1 '||' cmd-2
+ EOF
+}
+
+
+for (@ARGV) {
+ last if $_ eq '--';
+ if ($_ eq '--help') {
+ usage *STDOUT;
+ help *STDOUT;
+ exit;
+ }
+}
+
+my %opts;
+if (!Getopt::Std::getopts('h', \%opts)) {
+ usage *STDERR;
+ exit 2;
+}
+
+if ($opts{h}) {
+ usage *STDOUT;
+ help *STDOUT;
+ exit;
+}
+
+
+sub status_for($n) {
+ if ($n == -1) {
+ return 127;
+ } elsif ($n & 127) {
+ return $n & 127;
+ } else {
+ return $n >> 8;
+ }
+}
+
+my @AND = ('&&', 'AND');
+my @OR = ('||', 'OR');
+my @PIPE = ('|', 'PIPE');
+my @OPS = (@AND, @OR, @PIPE);
+
+my @CMD;
+for (@ARGV) {
+ if ($_ ~~ @OPS) {
+ system @CMD;
+ @CMD = ();
+ if ($_ ~~ @AND && $?) {
+ exit status_for($?);
+ } elsif ($_ ~~ @OR && !$?) {
+ exit 0;
+ } elsif ($_ ~~ @PIPE) {
+ ...
+ }
+ } else {
+ push @CMD, $_;
+ }
+}
+
+exit status_for(system @CMD);
+
+
+__END__
+
+=head1 NAME
+
+x - chain shell commands without creating a subshell
+
+=head1 SYNOPSYS
+
+x COMMANDS... [ '&&' / '||' / '|' ] COMMANDS...
+
+x COMMANDS... [ 'AND' / 'OR' / 'PIPE' ] COMMANDS...
+
+x -h
+
+=cut