Exit Full View

Feather2 / documentation / Commands.md

Commands

Feather has a built-in feature which makes running command-line programs as simple as possible. The default Configuration disables this feature for safety.

In these examples, we are going to use the standard echo command, but the same ideas work for any command.

class Greeter {
    fun greet() {
        $( echo Hello Nick ).run()
    }
}

This is the equivalent to println( "Hello Nick" ).

A command is built (but not run) using: $( ... ) The result is a Command object.

We can run commands using the run() method. Later we will look at alternatives to run() which are sometimes much more useful.

The contents of $( ... ) are similar to Smart Strings. i.e. we can include expressions within them. For example :

class Greeter {
    fun greet( name : String) {
        $( echo Hello $name ).run()
    }
}

Commands are tricky buggers though. The above has a major flaw. What if name == O'Reilly. The command will fail, because ' is a special character.

Here is the bug-free version :

$( echo 'Hello $name' ).run()

Feather spots that $name is being used within single quotes, and escape special characters. If you are interested in seeing the actual command :

val myCommand = $( echo 'Hello $name' )
println( myCommand )

The output is :

echo 'Hello O'\''Reilly'

Command Output

Redirection

We can redirect the output to a file :

$( echo Hello ) > File( "myFile.txt" )

Note that > is a Feather operator, which calls Command.redirect( File ).

There is also a String version for convenience :

$( echo Hello ) > "myFile.txt"

The return type is Redirect. Command and Redirect are both implementation of CommandBase. When we run a command or a redirect, we are using the run() method on CommandBase.

These redirects clear the contents of the file (if it exists).

If you want to append to the file, then :

$( echo Hello ) |> "myFile.txt"

This is equivalent to the >> operation of regular shell scripts. However, I couldn't use >> for technical reasons, so I chose |> instead. Sorry, I know this is confusing.

Running a redirection :

( $( echo Hello ) > "myFile.txt" ).run()

The additional brackets are required, because otherwise .run() would it would be applied to the String "myFile.txt". If, you find this too ugly, consider this alternative :

val sayHello = $( echo Hello ) > "myFile.txt"
sayHello.run()

IMHO, this is much more readable, but introduces an extra val. Pick whichever you prefer.

Redirecting stderr

There is no special operator for redirecting stderr. Call the method directly :

$( echo Hello ).redirectErr( "myFile.txt" )
$( echo Hello ).redirectErr( File( "myFile.txt" ) )

Redirect In

We can redirect a file as the input for a command.

$( grep Hello ) < "myFile.txt"

Pipes

The output from one command can be fed (piped) into another command :

$( ls *.txt ) | $( grep hello )

As usual, this does not run the command, so we still need to call run or eval etc.

val result = ( $( ls *.txt ) | $( grep hello ) ).eval()

Feather does not support piping stderr.

Summary

Feather commands do NOT work like shell scripts (such as bash). There are some superficial similarities, to help those who are familiar with writing shell scripts.

A Command is a just a Class, with methods. The only magic that feather introduces, which Java/Kotlin lack are :

  • Commands can be built using $( ... )
  • The contents of commands are similar to smart string, so they can include expressions using ${...}
  • These expressions are automatically escaped if they are within single quotes.
  • Feather has additional operators which call methods of a particular name :
    • > redirect( File ) or redirect( String )
    • |> redirect( File, append=true ) or redirect( String, append=true )
    • < redirectIn( File ) or redirectIn( String )
    • | pipe( CommandBase )

Back to Contents