diff options
-rw-r--r-- | README.markdown | 3 | ||||
-rw-r--r-- | bash/bashrc.d/apf.bash | 99 | ||||
-rwxr-xr-x | bin/apf | 44 | ||||
-rw-r--r-- | man/man1/apf.1 | 65 |
4 files changed, 111 insertions, 100 deletions
diff --git a/README.markdown b/README.markdown index 7a29e0c5..20bf847b 100644 --- a/README.markdown +++ b/README.markdown @@ -184,7 +184,6 @@ I also add completions for my own scripts and functions where useful. There are a few other little tricks in `bash/bashrc.d`, including: -* `apf` prepends arguments to a command with ones read from a file. * `bd` changes into a named ancestor of the current directory. * `fnl` runs a command and save its output and error into temporary files. * `hgrep` searches `$HISTFILE`. @@ -309,6 +308,8 @@ Installed by the `install-bin` target: * `rnda(1)` uses `rndi(1)` to choose a random argument * `rndf(1)` uses `rnda(1)` to choose a random file from a directory * `rndl(1)` uses `rndi(1)` to choose a random line from files +* `apf(1)` prepends arguments to a command with ones read from a file, + intended as a framework for shell functions. * `ax(1)` evaluates an awk expression given on the command line; this is intended as a quick way to test how Awk would interpret a given expression. * `bel(1)` prints a terminal bell character diff --git a/bash/bashrc.d/apf.bash b/bash/bashrc.d/apf.bash deleted file mode 100644 index 44de3a9e..00000000 --- a/bash/bashrc.d/apf.bash +++ /dev/null @@ -1,99 +0,0 @@ -# -# apf -- arg-prepend-file -- Prepend null-delimited arguments read from a file -# to a command's arguments before running it. This is intended as a way of -# implementing *rc files for interactive Bash calls to programs that don't -# support such files, without having to use broken environment variables (e.g. -# GREP_OPTIONS); this enables you to, for example, use arguments with shell -# metacharacters and spaces in them that you do not want expanded. -# -# For example, given this simple program in our $PATH, printargs: -# -# $ cat ~/.local/bin/printargs -# #!/bin/sh -# printf '%s\n' "$@" -# -# Which just prints its arguments: -# -# $ printargs a b c -# a -# b -# c -# -# We could do this: -# -# $ printf '%s\0' -f --flag --option '? foo bar *' > "$HOME"/.printargsrc -# -# $ apf "$HOME"/.printargsrc printargs a b c -# -f -# --flag -# --option -# ? foo bar * -# a -# b -# c -# -# We could then make a permanent wrapper function with: -# -# $ printargs() { apf "$HOME"/.printargsrc printargs "$@" ; } -# -# $ printargs a b c -# -f -# --flag -# --option -# ? foo bar * -# a -# b -# c -# -# $ printf '%s\n' !-2:q >> "$HOME"/.bashrc -# -# This means you can edit the options in the *rc file and don't have to -# redefine a wrapper function. -# -# If you actually want those options to *always* be added, regardless of -# whether you're in an interactive shell, you really should make an actual -# wrapper script. -# -apf() { - - # Require at least two arguments, give usage otherwise - if (($# < 2)) ; then - printf 'bash: %s: usage: %s ARGFILE COMMAND [ARGS...]\n' \ - "$FUNCNAME" "$FUNCNAME" >&2 - return 2 - fi - - # First argument is the file containing the null-delimited arguments - local argfile=$1 - shift - - # Check the arguments file makes sense - if [[ ! -e $argfile ]] ; then - printf 'bash: %s: %s: No such file or directory\n' \ - "$FUNCNAME" "$argfile" - return 1 - elif [[ -d $argfile ]] ; then - printf 'bash: %s: %s: Is a directory\n' \ - "$FUNCNAME" "$argfile" - return 1 - elif [[ ! -r $argfile ]] ; then - printf 'bash: %s: %s: Permission denied\n' \ - "$FUNCNAME" "$argfile" - return 1 - fi - - # Read all the null-delimited arguments from the file - local -a args - local arg - while IFS= read -rd '' arg ; do - args[${#args[@]}]=$arg - done < "$argfile" - - # Next argument is the command to run - local cmd=$1 - shift - - # Run the command with the retrieved arguments first, then the rest of the - # command line as passed to the function - command "$cmd" "${args[@]}" "$@" -} diff --git a/bin/apf b/bin/apf new file mode 100755 index 00000000..2d137c6b --- /dev/null +++ b/bin/apf @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +# Name self +self=apf + +# Require at least two arguments, give usage otherwise +if (($# < 2)) ; then + printf '%s: usage: %s ARGFILE COMMAND [ARGS...]\n' \ + "$self" "$self" >&2 + exit 2 +fi + +# First argument is the file containing the null-delimited arguments +argfile=$1 +shift + +# Check the arguments file makes sense +if [[ ! -e $argfile ]] ; then + printf '%s: %s: No such file or directory\n' \ + "$self" "$argfile" + exit 1 +elif [[ -d $argfile ]] ; then + printf '%s: %s: Is a directory\n' \ + "$self" "$argfile" + exit 1 +elif [[ ! -r $argfile ]] ; then + printf '%s: %s: Permission denied\n' \ + "$self" "$argfile" + exit 1 +fi + +# Read all the null-delimited arguments from the file +declare -a args +while IFS= read -rd '' arg ; do + args[${#args[@]}]=$arg +done < "$argfile" + +# Next argument is the command to run +cmd=$1 +shift + +# Run the command with the retrieved arguments first, then the rest of the +# command line as passed to the function +command "$cmd" "${args[@]}" "$@" diff --git a/man/man1/apf.1 b/man/man1/apf.1 new file mode 100644 index 00000000..67b3b25a --- /dev/null +++ b/man/man1/apf.1 @@ -0,0 +1,65 @@ +.TH APF 1 "August 2016" "Manual page for apf" +.SH NAME +.B apf +\- add arguments to a command from a file +.SH SYNOPSIS +.B apf +foorc +foo --bar baz +.SH DESCRIPTION +Add null-delimited arguments read from a file to a command's arguments before +running it. This is intended as a way of implementing *rc files for interactive +shell calls to programs that don't support such files, without having to use +broken environment variables (e.g. GREP_OPTIONS); this enables you to, for +example, use arguments with shell metacharacters and spaces in them that you do +not want expanded. + +For example, given this simple program in our $PATH, printargs: + + $ cat ~/.local/bin/printargs + #!/bin/sh + printf '%s\n' "$@" + +Which just prints its arguments: + + $ printargs a b c + a + b + c + +We could do this: + + $ printf '%s\0' -f --flag --option '? foo bar *' > "$HOME"/.printargsrc + + $ apf "$HOME"/.printargsrc printargs a b c + -f + --flag + --option + ? foo bar * + a + b + c + +We could then make a permanent wrapper function with: + + $ printargs() { apf "$HOME"/.printargsrc printargs "$@" ; } + + $ printargs a b c + -f + --flag + --option + ? foo bar * + a + b + c + + $ printf '%s\n' !-2:q >> "$HOME"/.bashrc + +This means you can edit the options in the *rc file, and don't have to redefine +a wrapper function. + +If you actually want those options to *always* be added, regardless of whether +you're in an interactive shell, you really should make an actual wrapper +script. +.SH AUTHOR +Tom Ryder <tom@sanctum.geek.nz> |