- 外部コマンド: execvp (p.46)
- cd: directory.c (p.44)
- 絶対パスなら cwd を置き換え, 相対パスなら cwd と結合, ~ なら HOME と結合, 引数なしなら HOME に設定して終了
path.resolve(char *a, char *b)
: a の末尾に / が無かったら / を付けて b と結合 - cwd のパスを正規化 (. や .. を取り除く)
- 絶対パスなら cwd を置き換え, 相対パスなら cwd と結合, ~ なら HOME と結合, 引数なしなら HOME に設定して終了
. = 削除
.. = 直前のディレクトリを削除
** := ([a-zA-Z0-9]+)(..)(.)
(nothing) = HOME
/** = 絶対パス
./** =
../** =
~/**
** = ./** と同じ
- dirs
- pushd
- popd
- history
- !!
1つ前のコマンドを再度実行 - !string
string で始まる最新のコマンドを実行 - ワイルドカード
*
のみ カレントディレクトリにある全てのファイル名 - prompt
$ prompt abc
abc prompt
Command: prompt $
$
- スクリプト
シェルの実行ファイルにscript_file
をリダイレクトで入力する - alias
- alias エイリアス一覧
- unalias command1
- !n
ヒストリで n 番目にあるコマンドを実行 - !-n
- ワイルドカード
*strings
strings*
- シェルスクリプト
- シェルスクリプト
command <args...>
var="string"
var=10
list=(val1 val2 val3)
$(( 1 + 1 ))
$var
command `command <args...>`-
# [[ $var = chicken ]] if expr; then elif expr; then else fi
-
# 1 2 3 or `seq 1 -l 10` for symbol in expr; do done
-
function symbol (){ echo "$1 $2" } symbol 'arg'
- 解析
- トークン
- LITERAL
- IF
- THEN
- ELIF
- ELSE
- FI
- FOR
- DO
- DONE
- EQUAL =
- LEFTPARE (
- RIGHTPARE )
- LEFTCURLY {
- RIGHTCURLY }
- SEMICOLON ;
- DOLLAR $
- lexer *
- AST
- Expression = command, var=, fn
- Statement = if, for, function
- トップレベルシンボルの優先順位: function > alias > 内部 command > 外部 command
- トークン
Program ::= Statement
Statement ::= Statement Statement | <IfStatement | ForStatement | FunctionStatement | ExpressionStatement> EOL
IfStatement ::= 'if' ExecuteExpression EOL 'then' Statement EOL
<'elif' Expression EOL 'then' Statement>*
<'else' Statement>? 'fi'
ForStatement ::= 'for' Literal 'in' LiteralExpression EOL 'do' Statement 'done'
FunctionStatement ::= 'function' Literal '()' '{' Statement '}'
ExpressionStatement ::= ExecuteExpression
#CommandStatement ::= LiteralExpression+ | '[[' LiteralExpression+ ']]'
#VariableStatement ::= Literal '=' LiteralExpression
YieldExpression ::= LiteralExpression | BackQuoteExpression | VariableExpression
LiteralExpression ::= Literal
BackQuoteExpression ::= '`' ExecuteExpression '`'
VariableExpression ::= '$' Literal
ExecuteExpression ::= CommandExpression | AssignExpression
CommandExpression ::= YieldExpression+ | '[[' YieldExpression+ ']]'
AssignExpression ::= Literal '=' YieldExpression
// ↓ for test command
ConditionalExpression ::= '(' ConditionalExpression ')'
| ConditionalExpression '&&' ConditionalExpression
| ConditionalExpression '||' ConditionalExpression
| '!' ConditionalExpression // 論理否定
| VarLiteral <'==' | '!='> VarLiteral
| Number <'-eq' | '-ne' | '-lt' | '-le' | '-gt' | '-ge'> Number
| <'-d' | '-e' | '-f' | '-L' | '-r' | '-s' | '-w' | '-x'> Literal
EOL ::= ';' | '\n'
// VarLiteral ::= '$' Literal | Literal
Literal ::= Literal Literal | <'a' | 'b' | ... | 'z' | '_'>
Number ::= ZNumber | NNumber ZNumber+
ZNumber ::= 0 | NNumber
NNumber ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
- リダイレクト
- 標準入力から入力を受け取る
- コマンドを cmd + arguments に分ける
- cmd -> 関数ポインタの Map から cmd に対応する関数を取り出し, arguments を引数に入れて実行する
- コマンド関数は 0 or 1 を返す. 出力は各関数内で行う
- TODO: 0 or 1 の戻り値はどう扱う?
- current working directory
- コマンド履歴: 先頭, 末尾, 検索
- DoublyLinkedList: まずこれのみで実装する
- Tri 木: !string string から始まるノードを検索し, その子の中から最も最新のノードを取り出す
- ディレクトリスタック: 一番上に push, pop
- エイリアスの Map
- コマンドの Map
- prompt
- main.c
- map.c: Map
- list.c: DoublyLinkedList