Table of parts: https://docs.google.com/document/d/1IIOkivkS0lV9QIL16b_OjT480BxZHQfKswvvS-CVZlw/view
Intro
Example: text editing
Graphical user interface - Графический интерфейс
Text interface, CLI, command line, командная строка, текстовый, терминал
You type text, computer shows text, line by line.
Псевдографический
Эмулятор терминала
Копирование и вставка
The text in a terminal emulator can be selected by mouse. Selection implies copying.
Middle (sometimes right) mouse button inserts the text at cursor position. Usually you can’t set cursor position by mouse.
Текст в эмуляторе терминала можно выделять мышкой. Выделение текста автоматически копирует его в буфер обмена. Средняя (иногда правая) кнопка мыши вставляет текст там, где курсор. Курсор обычно нельзя двигать мышкой.
Shell and REPL
Оболочка командной строки
Shell is the thing that reads your commands and executes them. In interactive mode it operates in REPL mode.
More detailed and complicated diagram:
This section describes where the final handling of events lans:
Main thing that flows through the tty is text. But there are additional things:
tty can also have multiple modes:
Readline - a library which uses interactive mode of terminal and allows better line editing, history, etc.
Each command line program (including the shell) have input and output. Bytes flow into the program from input and flows out of the program into output. The shell reads commands from whatever it’s input is connected to. Usually it is terminal emulator.
У каждой программы для командной строки есть ввод и вывод. Байты поступают на вход и “текут” в программу, или из программы на выход. Оболочка читает команды оттуда, к чему подключен её ввод. Обычно от подключен к эмулятору терминала.
Useful link: https://www.explainshell.com/explain.
Compiling simple C programs from console
$ gcc -Wall -ggdb myprogram.c -o myprogram
myprogram.c:1:1: warning: You have chosen the wrong job [-Wbadcode]
$ ./myprogram
Hello, world
Commands
Commands are things that get executed when you type some text into the shell and press Enter.
They can be:
“echo” command outputs it’s arguments separated by space
$ echo qqq www "eee rrr"
qqq www eee rrr
Command name and arguments is an array of strings that is passed to the program.
Имя команды и аргументы - это массив строк, передаваемый в программу.
$ some_program -flq --long-option=dsafdsaf file1 file2
Physical arguments:
Logical arguments:
-f, -l and -q are also called “flags”, as they don’t accept any argument here.
Terminology in Russian: которкая опция, флаг, длинная опция, аргумент, позиционный аргумент.
After "--" all arguments become positional:ende
$ other_program -r file1 -- file2 --looks-like-option -b -ut file3
Construct a command line for the following case:
#include <time.h> // for random
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
extern int optind;
extern char* optarg;
struct Opts {
int q;
int e;
int tool;
int adj;
};
void showadj(int adj, int capt) {
switch(adj) {
case 0: break;
case 1: if (!capt) printf("жёстко " ); else printf("Жёстко " ); break;
case 2: if (!capt) printf("неистово " ); else printf("Неистово " ); break;
case 3: if (!capt) printf("стремительно "); else printf("Стремительно "); break;
}
}
void showtool(int tool) {
switch(tool) {
case 0: break;
case 1: printf(" шваброй"); break;
case 2: printf(" щёткой"); break;
case 3: printf(" тряпкой"); break;
}
}
void show(struct Opts *opts, char** argv) {
if (!opts->q) {
printf("Мама ");
showadj(opts->adj, 0);
printf("мыла ");
} else {
if (!opts->adj) {
printf("Мыла ли мама ");
} else {
showadj(opts->adj, 1);
printf("ли мыла мама ");
}
}
if (!*argv) {
printf("раму");
} else {
while(*argv) {
char* next = *(argv+1);
printf("%s", *argv);
if (next) {
char* nextnext = *(argv+2);
if (nextnext) {
printf(", ");
} else {
printf(" и ");
}
}
++argv;
}
}
showtool(opts->tool);
switch (opts->q * 2 + opts->e) {
case 0: printf(".\n"); break;
case 1: printf("!\n"); break;
case 2: printf("?\n"); break;
case 3: printf("?!\n"); break;
}
}
void help() {
printf("getoptdemo - Demonstrate typical getopt_long(3)-based command-line argument parsing.\n");
printf("Usage: getoptdemo [options] [objects...]\n");
printf("Options and flags:\n");
printf(" -h, --help Show this message\n");
printf(" -Q, --question Make a question\n");
printf(" -E, --exclamation Finish with an exclamation sign\n");
printf(" -t, --tool=<number> Set 'tool' attribute\n");
printf(" -a, --adj[=<number>] Add an adjective\n");
exit(0);
}
static struct option long_options[] = {
{"help", no_argument, 0, 0 },
{"question", no_argument, 0, 0 },
{"exclamation", no_argument, 0, 0 },
{"tool", required_argument, 0, 0 },
{"adj", optional_argument, 0, 0 },
{0, 0, 0, 0 }
};
int main(int argc, char* argv[]) {
int i;
for(i=0; i<argc; i+=1) {
fprintf(stderr, "\"Physical\" command-line argument #%d: `%s`\n", i, argv[i]);
}
struct Opts opts = {0,0,0,0};
for(;;) {
int c;
int option_index;
c = getopt_long(argc, argv, "hQEt:a::", long_options, &option_index);
if (c == -1) break;
if (c == '?') return 1;
switch (c) {
case 0: break;
case 'h': option_index=0; break;
case 'Q': option_index=1; break;
case 'E': option_index=2; break;
case 't': option_index=3; break;
case 'a': option_index=4; break;
}
fprintf(stderr, "Option `%s`", long_options[option_index].name);
if (optarg) {
fprintf(stderr, " with value `%s`", optarg);
}
fprintf(stderr, "\n");
switch (option_index) {
case 0: // --help
help();
break;
case 1: // --question
opts.q = 1;
break;
case 2: // --exclamation
opts.e = 1;
break;
case 3: // --tool
opts.tool = atoi(optarg);
if (opts.tool < 1 || opts.tool > 3) {
fprintf(stderr, "Error: tool number is out of range [1,3]\n");
exit(1);
}
break;
case 4: // --adj
if (optarg) {
opts.adj = atoi(optarg);
if (opts.adj < 1 || opts.adj > 3) {
fprintf(stderr, "Error: adjective number is out of range [1,3]\n");
exit(1);
}
} else {
srand(time(NULL));
opts.adj = 1 + (rand() % 3);
}
break;
}
}
for(i=optind; i<argc; i+=1) {
fprintf(stderr, "Positional argument #%d: `%s`\n", i-optind+1, argv[i]);
}
show(&opts, argv+optind);
return 0;
}
Bash
Bash is a popular command line shell (and a programming language) in Linux.
I=0;
while [ $I -lt 10 ]; do
echo $I
I=$((I+1))
done
Bash is also a programming language (also called “shell” or “shell script”). There are branching and looping. Strings are interpolated (means various characters trigger special things).
Note: online bash https://www.tutorialspoint.com/unix_terminal_online.php.
I=0;
while [ $I -lt 10 ]; do
echo $I
I=$((I+1))
done
test -e myfile.txt; echo $?
test -e myfile.txt && echo Yes
test -e myfile.txt && test 5 -gt 4 && echo Both yes
if test -e myfile.txt && test 5 -gt 4; then echo Both yes; fi
if [ -e myfile.txt ] && [ 5 -gt 4 ]; then echo Both yes; fi
if [[ -e myfile.txt && 5 -gt 4 ]]; then echo Both yes; fi
test -e myfile.txt && echo Yes || echo No
if [ -e myfile.txt ]; then echo Yes; else echo No; fi
set -e
set -x
$ T=qwer
$ echo rrr $T hhh "qqq $T"
rrr qwer hhh qqq qwer
$ date
Fri Mar 20 19:43:35 FET 2015
$ echo qqq `date` www $(date)
qqq Fri Mar 20 19:43:35 FET 2015 www Fri Mar 20 19:43:35 FET 2015
$ echo "2*2+2 = $((2*2+2))"
2*2+2 = 6
rm *.txt
It gets "unwrapped" to sub-array, not just to single value.
You input a string. But command line arguments is an array of strings. Therefore shell needs to split your string into array.
Example:
$ args arg1 arg2\ arg3 arg4\" arg5 "arg6 arg7\ arg8"\ arg9 arg10 ""
[1]=arg1
[2]=arg2 arg3
[3]=arg4"
[4]=arg5
[5]=arg6 arg7\ arg8 arg9
[6]=arg10
[7]=
Split this to array like Bash do:
dsfs m s Kqq dsf" "qwe' 'qwe\ q1 "' 123 ''" ''"" 11\'\"
Implement "args" program that behaves like the one above (outputs all command line arguments, one on each line, with a line numbers).
Реализуйте программу "args" которая работает как та, что выше (выводит все аргументы командной строки, по одному на строку, с нумерацией строк).
Construct a command line that splits to the following parts:
Virtual and real file systems
VFS - виртуальная файловая система.
VFS is what the programs in Linux work with.
File descriptor - like HANDLE on Windows. A process-specific number pointing to some object in Linux kernel.
Домашний каталог пользователя
Home directory
Normalize the path: /1/2/3/.././../4/../..///a/b/c/././.
/1/2/3
Текущий каталог
Each process has current directory. There is no current drive like in Windows although.
Shell prompt typically shows the current directory.
Файловый дескриптор
File descriptor is an identifier of opened file (or something special instead of a file) in the given process. For example, the connection between shell and terminal emulator is also handled using file descriptors.
File descriptors may be pre-opened when a process starts.
The can be symbolic and hard links between files.
There can be symbolic links between directories, but not hard links.
Russian: символическая ссылка, жёсткая ссылка.
Text files
Array of lines. Line is array of characters ending in \n.
More bash
"concatenate"
Redirection of standard output into a file
Перенаправление стандартного вывода в файл
Redirection of standard input from a file
Перенаправление стандартного ввода из файла
Let's see what happens in detail:
Exersice 1
Try drawing the similar diagram set for "cat > file.txt" case.
Конвейеры
A pipeline of "echo qqq" and "cat".
Конвейер из "echo qqq" и "cat".
Example: cat file.txt | tr a b | cat > output.txt
Some easy text processing programs, for exercises:
Output 9 last lines of the source code of "args" program, reversing each line
Output in the reverse order the lines of the source code of "args" containing opening parenthesis "(" , changing the "m" character into double quote ", also changing the semicolon ; into the space character.
Выведите в обратном порядке строки исходного кода программы "args", содержащие открывающую скобку "(", заменяя символ "m" на двойную кавычку ", также заменяя точку с запятой ; на пробел.
Exchange two files.
Exchange two files using "ln" and "rm" commands.
Переменные окружения
Setting envvars in bash:
export ENVVAR=value
export Q = 4 # wrong
ENVVAR=value
export ENVVAR
PATH=$PATH:$HOME/bin
PATH=$HOME/bin:$PATH
A=b some_program
Статус возврата команды
$ cp dsf sadfdsaf
cp: cannot stat `dsf': No such file or directory
$ echo $?
1
if cp i_want_this_file.txt output.txt ; then
echo Allright
elif
echo Copying failed
fi
------------
while ! cp i_want_this_file.txt output.txt ; do
echo Cannot copy, do something
bash
echo Checking again...
done
echo Success
----------
cp first_variant.txt output.txt || cp second_variant output.txt
cp a.txt b.txt && cp b.txt c.txt
[ "3" == "4" ] && echo Do the impossible
Save the "while ! cp" fragment to new file, start it as Bash program, test it.
Сохраните фрагмент "while ! cp" в файл, запустите его как программу на Bash, протестируйте.
Go to your home directory. Create a file named qwe.txt with content Noooooo'o"ooo!.
Copy this file into ewq.txt.
Go to root directory.
Start program "cat" without arguments. Type the line "hello" into it.
Suspend the currently running program to background.
Output content of the file you have created.
List jobs.
Why this time "cat" finished and returned to shell, but previous "cat" was blocking the input?
Resume the backgrounded program and type "goodbye" into it.
Terminate the running program and return to shell.
Supplementary things (in Russian):
https://docs.google.com/document/d/1nZavuVuayZH_n-7yf_0jLDPFlasIurFVXAnlbJ-qlsI/edit?usp=sharing
Next parts