Skip to content

Repository files navigation

🖋️ Shell Pen

Generate BASH from BASH


Download the latest version by clicking one of the download links above or:

curl -o- https://shellpen.sh/installer.sh | bash

Getting Started

Once you have downloaded the latest version of ShellPen, source the library:

source shellpen.sh

You're now ready to start generating shell script source code!

Documentation

ShellPen offers three sources of documentation:

Using Pens

"Pens" are BASH functions used to author snippets of BASH source code.

Every pen is associated with a separate snippet of source code:

  • If you want to author 3 source code files, consider creating 3 separate pens

To create a pen:

shellpen pens new [pen name]

Or use the preferred shorthand:

shellpen [pen name]

A pen can have any name (which is a valid BASH function name):

  • No spaces are allowed
  • It is recommended to not name your pen :
  • None of the following characters: <>|()!

shellpen -

When writing to only one source, the conventional pen name is: -

Create Pen

shellpen -

$pen code

You will occassionally want to see the code written by your pen!

To do that, run [pen] code

Preview Generated Source

# Create a pen
shellpen -
# Write some source code
- echo"Hello, world!"# Preview the generated source code
- code
# => 'echo "Hello, world!"'

$pen cleanSlate

If at any time you wish to clear a pen's source code, run [pen] cleanSlate

# Create a pen
shellpen -
# Write some source code
- echo"Hello, world!"# Preview the generated source code
- code
# => 'echo "Hello, world!"'# Clear the pen's source code
- cleanSlate
# Preview the generated source code (now empty)
- code
# => ""

$pen putAway

Once you are finished with your pen, put it away via [pen] putAway

This will delete the pen and any source code associated with it.

# Create pen
shellpen -
# ...# Put pen away
- putAway
# Trying to use the - pen again will now result in an error
- code
# => -: command not found

shellpen extend

This page describes the basic features of ShellPen.

To extend the syntax, view the ⚙️ Extending Syntax Reference.

Writing Basics

The most basic pen function is writeln which appends one line of source code.

writeln

- writeln "Hello this is some code text"
- writeln "More code goes here"
- code
# => "Hello this is some code text\nMore code goes here"

Similar commands:

CommandDescription
writeAppends text without newlines but with indentation
writelnAppends a line of text with indentation
appendAppends text without newlines or indentation
appendlnAppends a line of text without indentation
prependPrepends text without newlines or indentation
prependlnPrepends a line of text without indentation

$ command

$ [command] [arguments] is an alias for writeln for "syntax sugar"

- $ someCommand "Argument1""Hello, world!"
- code
# => 'someCommand Argument1 Hello, world!'

When you want to generate code that calls a command, use $

  • Exceptions areechoandprintfwhich have useful generation helpers

$$ command

If you want the provided arguments wrapped in " quotes, use $$ instead:

- $$ someCommand "Argument1""Hello, world!"
- code
# => 'someCommand "Argument1" "Hello, world!"'

shebang

If you would like to add a "shebang" or "hashbang" to your source:

- shebang
- code
# => '#! /bin/bash'
  • You can also provide your own path, e.g. - shebang /usr/bin/env bash

function

Use function to start the definition of a function and } to finish:

- functionhello
- echo Hello
- }
hello() {
echo"Hello"
}

ℹ️ Levels of indentation are automatically added in functions et al.

main

Use main to add conventional code to run a function when the script is run:

- functionhello
- :
- }
- main hello
hello() {
:
}
[ "${BASH_SOURCE[0]}"="$0" ] &&"hello""$@"

Variables

Helper functions are provided for declaring different types of BASH variables:

  • var Defines a generic BASH variable
- var x = 10
x=10
  • local Defines a local variable for use in a BASH function
- fn hello
- local x = 10
hello() {
local x=10
}
  • int declares a BASH integer value variable
- int x = 10
declare -i x=10
  • array declares a single-dimensional BASH array
- array x
declare -a x
With Items
- array x Hello World '$@'
declare -a x=("Hello""World""$@")
  • "Map" is shorthand for defining an associative-array:
- map x
declare -A x
With Items
- map x [Hello]=World [Foo]="Foo Bar"
declare -A x=([Hello]="World" [Foo]="Foo Bar")

Output

ShellPen provides helpers for generating echo and printf commands.

echo

  • Any commands provided to echo will be wrapped in " quotes
- echo"Hello, world" foo bar
echo"Hello, world""foo""bar"

printf

  • printf specifically supports providing a ' single quoted formatter string
- printf"Hello"
printf"Hello"
With Formatter
- printf'%s'"Hello"
printf'%s'"Hello"
With Flags
- printf -v varname '%s' -- "Hello"
printf -v "varname"'%s' -- "Hello"

toStderr

  • Any command can have output sent to STDERR by prepending the command with toStderr
- toStderr echo"Hello"
echo"Hello">&2
Arbitrary Command
- toStderr $ myCommand arg1 arg2
myCommand arg1 arg2 >&2

toFile

  • Any command can have output sent to a file by prepending the command with toFile [path]
- toFile log.log echo"Hello"
echo"Hello">"log.log"
Arbitrary Command
- toFile log.log $ myCommand arg1 arg2
myCommand arg1 arg2 >"log.log"

Conditionals

if / fi

  • if conditionals are supported (thenis an optional keyword)
- if [ '$#'-eq 0 ]
- comment Hello
- elif [ '$#'-eq 1 ]
- else
- echo"Hello, world"
- fi
if [ $#-eq 0 ]
then# Hello:elif [ $#-eq 1 ]
then:elseecho"Hello, world"fi

ℹ️ Empty blocks (or those with only comments) automatically have a : added

case / option / esac

  • case / esac conditionals are supported
    • option is used for options
    • :: is used in place of ;; for closing each option
- case'$1'in
- option "foo"
- echo "Hello from foo"
- ::
- option "bar"
- ::
- option '*'
- echo "Other option!"
- ::
- esac
case"$1"in
foo)
echo"Hello from foo"
;;
bar)
:
;;
*)
echo"Other option!"
;;
esac

[ ... ] AND / OR

  • One-liner conditionals are supported with the use of AND and/or OR
- [ '$#'-eq 0 ] AND toStderr echo"At least one argument is required"
[ $#-eq 0 ] &&echo"At least one argument is required">&2
{ ... ; ... }
  • One liner statements with { ... } are supported using , in place of ;
- [ '$#'-eq 0 ] AND { toStderr echo"Argument is required" , return 1 , }
[ $#-eq 0 ] && { echo"Argument is required">&2;return 1; }

Loops

for

  • for loops are supported (dois an optional keyword)
- forargin'"$@"'
- echo Argument: '$@'
- done
forargin"$@"doecho"Argument:""$@"done

while

  • while loops are supported (dois an optional keyword)
- while [ '$#'-gt 0 ]
- echo Argument: '$1'
- shift
- done
while [ $#-gt 0 ]
doecho"Argument:""$1"shiftdone

Arithmetic

{{ ... }}

  • (( ... )) arithmetic is supported using {{ ... }} in place of parenthesis
- int i=42
- {{ i++ }}
declare -i i=42
(( i++))

Pipes | STDIN

It's common to need to use | pipes in generated BASH source code.

\|

  • Pipes are supported by providing an escaped \| in place of a | pipe character
- echo'$1'\| $ sed "'s/foo/bar/'"\| $ head -1 \| $ xargs -n1 echo
echo"$1"| sed 's/foo/bar/'| head -1 | xargs -n1 echo

fromStdin

  • Any command can accept input from STDIN by prepending the command with fromStdin [source of stdin]
- while'IFS=""'read -r line \|\| [ -n'"$line"' ]
- echo'$line'
- fromStdin some/file.txt done
while IFS=""read -r line || [ -n"$line" ]
doecho"$line"done< some/file.txt

ℹ️ The previous example uses an escaped OR (\|\|) instead of OR

  • Because OR adds an || after the previous command's output, this would result in the || being added after the while's do is automatically added.

fromFile

  • Any command can accept STDIN from a file path by prepending the command with fromFile [file path]
    • This is the same as fromStdin but wraps provided arguments in"
- while'IFS=""'read -r line \|\| [ -n'"$line"' ]
- echo'$line'
- fromFile some/file.txt done
while IFS=""read -r line || [ -n"$line" ]
doecho"$line"done<"some/file.txt"

fromCommand

  • Any command can accept input from a command by prepending the command with fromCommand "[command with args]"
- var text = '"$(<"$filePath")"'
- while'IFS=""'read -r line \|\| [ -n'"$line"' ]
- echo'$line'
- fromCommand "printf '%s' \"\$text\""done
text="$(<"$filePath")"while IFS=""read -r line || [ -n"$line" ]
doecho"$line"done<<(printf '%s'"$text")

fromText

  • Any command can accept input from a string with fromText "string"
- while'IFS=""'read -r line \|\| [ -n'"$line"' ]
- echo'$line'
- fromText '$text'done
while IFS=""read -r line || [ -n"$line" ]
doecho"$line"done<<<"$text"

About

✒️ Shell Script Code Generation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages