diff options
-rwxr-xr-x | bin/x | 178 |
1 files changed, 112 insertions, 66 deletions
@@ -1,94 +1,140 @@ -#!/bin/sh -set -eu +#!/usr/bin/env perl -usage() { - cat <<-'EOF' +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... [ '&&' / '||' / '|' ] COMMANDS... + x COMMANDS... [ 'AND' / 'OR' / 'PIPE' ] COMMANDS... x -h - EOF + EOF } -help() { - cat <<-'EOF' +sub help($fh) { + print $fh <<~'EOF' Options: -h, --help show this message COMMAND the command to be executed - && "AND" logical operator - || "OR" logical operator - | pipe operator + '&&' / 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 - # same as: + # equivalent to: $ time sh -c 'sleep 1 && sleep 2' Notify when either of the commands finish: $ boop x cmd-1 '||' cmd-2 - EOF + 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; } -for flag in "$@"; do - case "$flag" in - --) - break - ;; - --help) - usage - help - exit - ;; - *) - ;; - esac -done - -while getopts 'h' flag; do - case "$flag" in - h) - usage - help - exit - ;; - *) - usage >&2 - exit 2 - ;; - esac -done -shift $((OPTIND - 1)) - - -CMD='' -for arg in "$@"; do - case "$arg" in - '&&'|'||') - set +e - sh -c "$CMD" - STATUS=$? - set -e - CMD='' - if [ "$arg" = '&&' ] && [ "$STATUS" != 0 ]; then - exit "$STATUS" - elif [ "$arg" = '||' ] && [ "$STATUS" = 0 ]; then - exit 0 - fi - ;; - *) - CMD="$CMD${CMD:+ }'$arg'" - ;; - esac -done - -sh -c "$CMD" +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 + |