class: center, middle, title title: CLI-fu
- Programs
- Input
- One file
- Two arrays of strings
- Output
- Two files
- An integer
- Input
- In system calls, files are just integers
- STDIN (file descriptor 0)
- STDOUT (file descriptor 1)
- STDERR (file descriptor 2)
// writes to stdout
write(1, "Hello, world!\n", 14);
# writes to stdout
puts "Hello, world!"
- ARGV (vector of arguments)
- Name of program is the first argument
int main(int argc, char **argv) {
int i;
for (i=0; i<argc; i++) {
printf("[%d]=%s\n", i, argv[i]);
}
}
puts "[0]=#{$0}"
ARGV.each_with_index do |a,i|
puts "[#{i}]=#{a}"
end
- Treated as set of key-value pairs
- List of strings split on first "=" character
int main(int argc, char **argv, char **env) { // not portable
int i;
for (i=0; env[i]; i++) {
printf("ENV[%d]: %s\n", i, env[i]);
}
}
- "Exit status", "Error code"
- 0 = everything OK
- not 0 (often 1) = something went wrong
int main(void) {
return 1;
}
$ true ; echo $?
# => 0
$ false ; echo $?
# => 1
- Find the command(s) to run
- Wire up standard files
- Execute the pipeline
- Do control flow based on exit codes
$ /bin/echo pizza | grep z
# /bin/echo = fully qualified, no need to search
# grep = check each \`:`-separated entry in \`$PATH`
# open pipe = set of two files (UNIX sockets)
# run /bin/echo with fd1 = write end of pipe
# run /bin/grep with fd0 = read end of pipe
if # condition
then # command
elif # condition
then # command
else # command
fi
case ... in
pattern)
# command
;;
esac
while # condition
do # command
done
for x in ...
do # command
done
if # command
then # command
elif # command
then # command
else # command
fi
case ... in
pattern)
# command
;;
esac
while # command
do # command
done
for x in ...
do # command
done
$ which [
# => /bin/[
$ if [ -z "$var" ]
# if $var is empty:
# runs ["[", "-z", "", "]"]
- Use
[[ ... ]]
if your shell supports it - POSIX allows
[[
and]]
to have different semantics bash
andzsh
both do this- More resilient (syntax-enhanced)
$ var="directory with spaces"
$ [ -d $var ]
# dash: 2: [: directory: unexpected operator
# bash: [: too many arguments
## works fine in zsh... where arg splitting is different
- Can set variables
- ENV variables are inherited
export
creates new ENV vars&&
and||
(&&
binds tightly)
-
Backslash = escape character
-
Single quotes retain everything
-
Double quotes retain everything except:
$
=> parameter expansion- ` => command substitution
- Backslash only escapes:
$ ` " \ <newline>
-
Always need to be quoted:
| & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
-
Sometimes need to be quoted:
* ? [ # ~ = %
-
HEREDOCs
awk
sed
xargs
jq