#!/usr/bin/env perl use v5.34; use strict; use warnings; use feature 'signatures'; no warnings 'experimental'; 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); # FIXME: implement manpage in pod __END__ .TH x 1 1970-01-01 "x latest" "x user manual" .SH NAME x - chain shell commands without creating a subshell. .SH SYNOPSYS \fBx\fR [\fIOPTIONS\fR] COMMAND... [ \fI'&&'\fR / \fI'||'\fR / \fI'|'\fR ] COMMAND... .SH DESCRIPTION \fBx\fR is a \m[blue]\fBtool\fP\m[], from .pdfhref W -D https://euandre.org/ -- The best website ever . .SH OPTIONS .TP \fB-h\fR, \fB--help\fR Show help text. .SH OPERATORS