-
Notifications
You must be signed in to change notification settings - Fork 1
Home
-
ํ ์คํธ ์ ์ถ๋ ฅ ํ๊ฒฝ, CLI (Command Line Interface)
-
๋ช ๋ น์ ์ฒ๋ฆฌํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ ์ ์๋ ๊ทธ๋ฅ ์ธํฐํ์ด์ค์ด๋ค.
-
ํฐ๋ฏธ๋์ ํํ๋ก ํ๋์จ์ด์ ์ํํธ์จ์ด๊ฐ ์๋ค.
minishell
์ ๊ฒฝ์ฐ ์ํํธ์จ์ด๊ฐ๋ ์ ํฐ๋ฏธ๋์ด๋ค. -
ํฐ๋ฏธ๋์ ๊ทธ๋ํฝ ์ธํฐํ์ด์ค๋ฅผ ํ์ํ๊ณ ์๊ณผ ์ํธ ์์ฉํ ์ ์๋ ํ๋ก๊ทธ๋จ์ด๋ค.
-
ํฐ๋ฏธ๋์ ํ ์คํธ ์ ๋ ฅ ๋ฐ ์ถ๋ ฅ ํ๊ฒฝ์ด๋ค.
๐ก ํต์ฌ์ ๊ทธ๋ฅ ํ๊ฒฝ์ด๋ค! ์ปดํจํฐ์ ์ํธ์์ฉํ๊ณ ๋ช ๋ น์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ์์ ์ญํ ์ด๋ค.
- ์ปดํจํฐ์ ์ํธ์์ฉํ ์ ์๋ ์์ฉ ํ๋ก๊ทธ๋จ
- ์ ๋ ฅ๊ณผ ์ถ๋ ฅ์ ํ์ผ์์ ๊ฐ์ ธ์ค๋๋ก redirection
- ์ปค๋งจ๋๋ผ์ธ ์ธํฐํ์ด์ค(CLI)๋ก ๊ตฌํ๋ ํ๋ก๊ทธ๋จ
- ์ปดํจํฐ์ ๋ช ๋ น์ ๋ด๋ฆฌ๊ธฐ ์ํ ์ธํฐํ์ด์ค ์ญํ
minishell command_line Execute Flow
command_line
โtokenize
โsyntax check
โAST parsing tree
โexecute_command_line(AST)
Execute Flow Image
- option1 ) Parsing Linked List
- Parsing Linked List
- option2 ) AST Parsing Tree (์ถ์๊ตฌ๋ฌธํธ๋ฆฌ)
- ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ฝ๊ณ ํด์ํ ๋ ์ฃผ๋ก ์ฐ์
- ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ๋ฌธ๋ฒ์ ๋ฐ๋ผ ์์ค์ฝ๋๋ฅผ ํธ๋ฆฌ ์๋ฃ๊ตฌ์กฐ ํํ๋ก ๊ด๋ฆฌ
- ์ถ์๊ตฌ๋ฌธํธ๋ฆฌ๋ก ํ์ฑ์ ํ๋ฉด ๋์ค์ ์์ค ์ฝ๋์ ์์ ๋ฐ ์ ์ง๋ณด์๋ฅผ ํ ๋ ๋ ํธ๋ฆฌํ ๊ฒ์ด๋ผ ํ๋จํ์ฌ ์ ํ
- ๊ฐ๋ ์ฑ์ด ์ข์ ์๋ฃ๊ตฌ์กฐ๋ก ๋ง๋ค ์ ์๋ค๋ ์ฅ์ ์ด ์์
- But, ์ ์ํ ํ๋ก๊ทธ๋๋ฐ ๋ฌธ๋ฒ์ด ์ฌ๋ฐ๋ฅด์ง ์์ ๋ ์ฌ๊ฐํ ๋ฌธ์ ๋ฅผ ๋ฐ์์ํฌ ์ ์์
- ์ฐ์ฐ์ ์ค์ฌ์ผ๋ก ์์ฝํด์ ํํํ๋ค
- AST ๊ตฌ์กฐ ์๊ฐํ ํ์ .. ( โ๏ธ
๋์ ..
)
What is EBNF?
๐ก ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๊ตฌ๋ฌธ์ ๊ธฐ์ ํ๋ ๋ฐ ๋งค์ฐ ์์ฐ์ค๋ฌ์ด ํ๊ธฐ๋ฐฉ๋ฒ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ๋ฌธ๋ฒ ์ ์ ๋ฐฉ๋ฒ๋ก- ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๊ตฌ๋ฌธ์ ๊ธฐ์ ํ๋๋ฐ ๋งค์ฐ ์์ฐ์ค๋ฌ์ด ํ๊ธฐ๋ฒ
- ๊ธฐ์กด์ BNF(Backus-Naur Form)์์ ๋ ๋ฐ์ ๋ ํ๊ธฐ๋ฒ
- ๊ธฐ์กด์
์ฌ๊ท์ ์ ์
์์๋ฐ๋ณต์ ์ ์
๋ก ๋ ๊ฐํธํ๊ฒ ๋ํ๋ผ ์ ์๊ฒ ํจ - {} : 0๋ฒ ์ด์ ๋ฐ๋ณต
- [ ]: 0๋ฒ ํน์ 1๋ฒ ๋ฐ๋ณต (option)
- ๋ง์ง๋ง์ด ์ฐ์ ์์๊ฐ ๋์ ๊ฒ์ด๋ค
Blackhole-Shell EBNF
<program> -> { <pipe_line> }
<pipe_line> -> <command> { '|' <pipe_line> }
<command> -> [ <simple_command> ][ <redirects> ]
<simple_command> -> <exec_path> { <argv> }
<redirects> -> <io_redirect> { <redirects> }
<io_redirect> -> <redirect_op> <file_path>
<redirect_op> -> '>' | '>>' | '<' | '<<'
<exec_path> -> word | "word" | 'word'
<file_path> -> word | "word" | 'word'
<argv> -> word | "word" | 'word'
blackhole-shell parse-execute flow diagram
typedef enum e_type
{
T_NULL,
T_WORD,
T_REDIRECT,
T_PIPE
} t_type;
typedef struct s_token
{
t_type type;
char *value;
} t_token;
-
T_NULL
T_WORD
T_REDIRECT
T_PIPE
์ผ๋ก ๊ตฌ๋ถ๋๊ณvalue
์ ๋ด์์ ์ฌ์ฉ - ํ ํฐ์ ๋ชฉ์ ๋ณ๋ก ๊ตฌ๋ถํจ
์ ๋ ฅ ์คํธ๋ง์ ์ฝ์ด์ ํ ํฐ ํํ๋ก ๋ถ๋ฆฌํ์ฌ ๋ฐํ (๊ตฌ๋ฌธ ๋ถํด ๋ฐ ์ฌ๋ฐ๋ฅธ ๊ตฌ๋ฌธ ํํ(ํ ํฐ์ด) ์ผ๋์ง ํ์ธํ๋ ์ญํ )
-
get_token
ํจ์๋ก AST ํ์ฑ์ ํ๋ฉด์Syntax Check
์ ํจ๊ปvalue
๋ฅผ ๋ฐํ -
match
โfetch_token
โget_token
โlexer
match(token)
char *match(t_type type)
{
t_token token;
token = fetch_token(UPDATE);
if (token.type == type)
return (token.value);
else
throw_error_syntax(token);
return (NULL);
}
fetch_token(fetch_type)
- GET : ํ์ฌ ํ ํฐ value ๋ฐํ
- UPDATE : ํ ํฐ ์ ๋ฐ์ดํธ ๋ฐ ์ด์ ํ ํฐ value ๋ฐํ
t_token fetch_token(t_fetch_type type)
{
static t_token token;
t_token prev_token;
prev_token = token;
if (type == GET)
return (token);
else if (type == UPDATE)
token = get_token();
return (prev_token);
}
get_token
- ๋ค์ ํ ํฐ ๋ฐํ
t_token get_token(void)
{
char *begin;
char *end;
t_token token;
int flag;
token.type = T_NULL;
token.value = NULL;
flag = lexical_analyzer(&token, &begin, &end);
if (g_manager.rc >= (int)ft_strlen(g_manager.command_line))
return (token);
if (flag == ERROR_FLAG)
g_manager.exit_code = EXIT_SYNTAXERR;
token.value = bs_calloc(end - begin + 1, sizeof(char));
if (!token.value)
return (token);
if (!ft_strlcpy(token.value, begin, end - begin + 1))
return (token);
g_manager.rc += end - begin;
return (token);
}
์ ๋ ฅ ์คํธ๋ง์ (์ฌ๊ท ํ๊ฐ) ํ์ฑ, ํด๋น ์ ๋ ฅ์ AST ๋ฅผ ์์ฑํ์ฌ ๋ฐํ
- ์ฌ๊ท์ ์ผ๋ก
token
์Tree
๊ตฌ์กฐ๋ก ํ์ฑํ๋ฉด์AST
์์ฑ -
token
์ ์ฝ๊ณ , ํด๋น ๋ฌธ๋ฒ์ ๋ง๋์งSyntax Error
ํ์ธ
AST ๋ฅผ ์ฝ์ผ๋ฉด์ ํด์ ๋ฐ ์คํ
-
Heredoc
์คํ- ํ์ฑ๋
AST
์ ๋ฐ๋ผheredoc
๋จผ์ ์คํ
- ํ์ฑ๋
-
Redirection
ํด์ ๋ฐ ์คํํด์-
redirect_op
์ฒดํฌ -
in
out
heredoc
append
์คํ
-
-
Pipe
ํด์ ๋ฐ ์คํ-
U_PIPE
๊ฐฏ์์ ๋ฐ๋ผ ์์ ํ๋ก์ธ์ค ์์ฑ ๋ฐ ์คํ
-
-
Command
๊ฐฏ์-
single_command
์ผ ๋-
single_command
-builtin
-
single_command
-general
-
-
multi_command
์ผ ๋-
fork()
๋ก ์์ ํ๋ก์ธ์ค ์์ฑ ๋ฐ ์คํ
-
-
-
< infile
: ์กด์ฌํ๋ infile์ ์ ๋ ฅ -
> outfile
: ๊ฒฐ๊ณผ๋ฅผ outfile๋ก ์ถ๋ ฅ -
<< heredoc
: ์ ๋ ฅ๋ฐ์ ๋ฌธ์์ด์ infile๋ก ๋ฐ๊ณ end_text ๋๋ EOF๋ก ์ ๋ ฅ ์ค๋จ -
>> append
: ๊ฒฐ๊ณผ๋ฅผ outfile์ ์ด์ด์ฐ๊ธฐ
- ํ๋ก์ธ์ค๊ฐ์ ๋น๋๊ธฐ์ ์ธ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ ๋ฐฉ๋ฒ
- Software Interrupt
- standard signals
- (2) SIGINT :
ctrl-c
- Action : Term
- (3) SIGQUIT :
ctrl-\
- Action : Core
- ์ฝ์ด ๋คํ : ํน์ ์์ ์ ์ฝ์ด ํ์ผ์ ๋ง๋ค๊ณ ์ข ๋ฃํจ. ์ฝ์ด ํ์ผ์ด๋ ๋น์ ์์ ์ผ๋ก ํ๋ก์ธ์ค๊ฐ ์ข ๋ฃ๋๋ ๊ฒฝ์ฐ, ํ๋ก์ธ์ค์ ์์ญ์ ์ฝ์ด ํ์ผ์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ํ๋ก๊ทธ๋จ์ ์คํ ์์น์ ์ ์ฅํ๋ ํ์ผ
- (2) SIGINT :
- bash์์์ signal ๋์
- SIGINT : print a new propmt on a newline
- SIGQUIT : do nothing
- ์๊ทธ๋์ ์๋์ง๋ง ์ถ๊ฐ๋ก, EOF
ctrl-d
๋ฅผ ๋ง๋๋ฉด exit the shell
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
-
signo
: ์๊ทธ๋์ ์ด๋ฆ -
func(int signo)
: signal handler ํจ์-
SIG_IGN
: ์๊ทธ๋ ๋ฌด์ -
SIG_DFL
: ๋ํดํธ ์๊ทธ๋ ์ฌ์ฉ - ์ฌ์ฉ์ ์ ์ ํจ์
-
- create a child process
- pid๊ฐ ๋ค๋ฅธ ์๋ก์ด ํ๋ก์ธ์ค๋ฅผ ์ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น
- ํธ์ถํ ํ๋ก์ธ์ค๋ฅผ ์๋ก์ด ๊ณต๊ฐ์ผ๋ก ๋ชจ๋ ๋ณต์ฌํ๋ฉฐ ๋ถ๋ชจ ํ๋ก์ธ์ค์ ์์ ํ๋ก์ธ์ค๋ ๊ฐ์ ์งํ
- execute program
- ํ์ฌ ์คํ๋๊ณ ์๋ ํ๋ก๊ทธ๋จ์ด ์๋ก ์ด๊ธฐํ๋ stack, heap, data segments์ ํจ๊ป ์๋ก์ด ํ๋ก๊ทธ๋จ์ผ๋ก ๋์ฒด๋จ
-
fork
๋ ๋ถ๋ชจ ํ๋ก์ธ์ค์ signal handler๋ฅผ ๋ณต์ฌํด์ ๊ทธ๋๋ก ์ฌ์ฉ -
execve
๋ signal handler๊ฐ default๋ก reset ๋จ. ํ์ง๋ง Ignored ์ํ์๋ค๋ฉด ๋ณํ์ง ์์.
A child created via fork(2) inherits a copy of its parentโs signal dispositions. During an execve(2), the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged.
The dispositions of any signals that are being caught are reset to the default (signal(7)).
POSIX.1 specifies that the dispositions of any signals that are ignored or set to the default are left unchanged.
-
SIGINT
(ctrl+c)- ๊ฐํ(
\n
) ์ถ๋ ฅ (์ prompt๋ฅผ ์๋ ์ค์ ์ถ๋ ฅํ๊ธฐ ์ํจ) - ๋ฒํผ ๋น์ฐ๊ธฐ โ
rl_replace_line()
- ์ prompt ๋์ฐ๊ธฐ โ
rl_on_new_line()
,rl_redisplay()
- ๊ฐํ(
-
SIGQUIT
(ctrl+) : do nothing โSIG_IGN
์ฌ์ฉ - init_signal.c ์ฐธ๊ณ
-
SIGINT
(ctrl+c)-
execve
์์SIG_DFL
default ๋์ - ์ฃผ์! ๋๊ธฐ์ค์ธ ๋ถ๋ชจ ํ๋ก์ธ์ค๋ ์ข ๋ฃ๋๋ฉด ์ ๋จ
-
-
SIGQUIT
(ctrl+)-
execve
์์SIG_DFL
default ๋์ - ์ฃผ์! ๋๊ธฐ์ค์ธ ๋ถ๋ชจ ํ๋ก์ธ์ค๋ ์ข ๋ฃ๋๋ฉด ์๋จ
-
-
bash์ ๋ด์ฅ๋ ๋ช ๋ น์ด๋ก ์คํํ์ผ์ด ๋ฐ๋ก ์์ ์ ์๋ค
-
type
์ผ๋ก ํ์ธ ํ ์ ์๋ค- builtin์ธ ๊ฒฝ์ฐ
[command] is a shell builtin
- builtin์ธ ๊ฒฝ์ฐ
-
simple command์ ์ฒซ๋ฒ์งธ word๋ก builtin์ ์ฌ์ฉํ๋ฉด, ์์ ๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ invokingํ์ง ์๊ณ ๋ฐ๋ก ์คํํจ
Builtin commands are contained within the shell itself. When the name of a builtin command is used as the first word of a simple command (seeย Simple Commands), the shell executes the command directly, without invoking another program. Builtin commands are necessary to implement functionality impossible or inconvenient to obtain with separate utilities.
(GNU bash ๊ณต์๋ฌธ์)
- simple commands โ Blackhole-shell EBNF ์ฐธ๊ณ
-
builtin command๊ฐ simple command์ผ ๊ฒฝ์ฐ, builtin command๊ฐ simple command๊ฐ ์๋ ๊ฒฝ์ฐ, general command์ธ ๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ๋ก์ธ์ค fork ์ ๋ฌด๊ฐ ๋ฌ๋ผ์ง๊ณ , ๊ทธ์ ๋ฐ๋ฅธ signal ์ฒ๋ฆฌ๋ ๋ฌ๋ผ์ง๋ค.
-
์ง์ ๊ตฌํํ builtin commands
=>
echo
,cd
,pwd
,export
,unset
,env
,exit