1. Open file descriptors table maps number (file descriptor - FD) into actual
file to which output will be written.
+----+------------+
| FD | File |
+----+------------+
| 0 | /dev/vc/1 |
+----+------------+
| 1 | /dev/vc/1 |
+----+------------+
| 2 | /dev/vc/1 |
+----+------------+
| ... |
2. Redirection operators (shell) affect (change) only 'File' column of the
table. So, if program writes to FD=5 (write(5,..); call) you can _not_
force it to write to another FD with shell redirection - you can only
change the content of 'File' column in the FD=5 row (i.e to what file FD=5
is mapped) and through that change to where output arrives at the end (to
which file).
3. '/dev/stdout' and '/dev/stderr' are _not_ an actual files, they're _links_
to what is _now_ opened at FD=1 and FD=2 correspondingly. I.e links to
file specified in 'File' column of FD=1 and FD=2 rows.
# ls -l /dev/stdout /dev/stderr
lrwxrwxrwx 1 root root 15 Sep 30 07:56 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Sep 30 07:56 /dev/stdout -> /proc/self/fd/1
4. In construction like
f() {
echo "abc"
return 0
}
res=$(f)
function f() result are sent through pipe to the caller. I think, this is
not clear to say, that result are sent through "stdout", though it's
correct, since "stdout" is _not_ an actual file - it's a link to what is
now opened at file descriptor 1, and now there will be pipe. By default,
when function invoked through command substitution (function will be
executed in a subshell), pipe is opened for writing at FD=1 for child
process (function) and for reading at FD=3 for caller process. So, if you
use something like
echo "abc"
"abc" will be written into pipe (because `echo` always writes to FD=1). But
if you want, that the way how we send result does not affect function's
code, we should move 'pipe' from FD=1 into some unused FD and restore
original FD=1 content.
exec 7>&1 1>&2
When result will be ready, we move 'pipe' back to FD=1 and `echo` result
into it.
exec 1>&7-
echo "result"
Note, that for all child subshells pipe will be opened as well.
Example. Illustrates complete implementation, with several stacked functions
returning result through pipe.
#!/bin/bash
log='./t.log'
read_f='/dev/null'
rm -f $log
f2() {
echo "f2(): SUBSH=$BASH_SUBSHELL" >>$log
echo "f2(): BASHPID[$BASHPID]:" >>$log
lsof -a -p $BASHPID -d '^mem,^cwd,^rtd,^txt' >>$log
echo "f2(): stdout-1: ghi"
echo "f2(): stderr-1: klm" >/dev/stderr
echo "f2(): Before moving pipe somewhere" >>$log && read -n1 < $read_f
eval "exec $save_pipe>&1 1>&$save_stdout-"
echo "f2(): BASHPID[$BASHPID]:" >>$log
lsof -a -p $BASHPID -d '^mem,^cwd,^rtd,^txt' >>$log
echo "f2(): stdout-2: ghi"
echo "f2(): stderr-2: klm" >/dev/stderr
echo "f2(): Before exit f2()" >>$log && read -n1 < $read_f
return 0
}
f() {
echo "f(): SUBSH=$BASH_SUBSHELL" >>$log
echo "f(): \$\$[$$]:" >>$log
lsof -a -p $$ -d '^mem,^cwd,^rtd,^txt' >>$log
echo "f(): BASHPID[$BASHPID]:" >>$log
lsof -a -p $BASHPID -d '^mem,^cwd,^rtd,^txt' >>$log
echo 'f(): stdout-1: abc'
echo 'f(): stderr-1: def' >/dev/stderr
echo "f(): Before moving pipe somewhere" >>$log && read -n1 < $read_f
eval "exec $save_pipe>&1 1>&$save_stdout-"
echo "f(): BASHPID[$BASHPID]:" >>$log
lsof -a -p $BASHPID -d '^mem,^cwd,^rtd,^txt' >>$log
echo 'f(): stdout-2: abc'
echo 'f(): stderr-2: def' >/dev/stderr
echo "f(): Before calling f2()" >>$log && read -n1 < $read_f
eval "exec $save_stdout>&1"
v=$(f2)
echo "-$v-"
eval "exec $save_stdout>&-"
echo "f(): BASHPID[$BASHPID]:" >>$log
lsof -a -p $BASHPID -d '^mem,^cwd,^rtd,^txt' >>$log
echo "f(): Before restoring pipe" >>$log && read -n1 < $read_f
exec >&$save_pipe-
echo 'f(): stdout-3: abc'
echo 'f(): stderr-3: def' >/dev/stderr
echo "f(): BASHPID[$BASHPID]:" >>$log
lsof -a -p $BASHPID -d '^mem,^cwd,^rtd,^txt' >>$log
echo "f(): Before exit f()" >>$log && read -n1 < $read_f
return 0
}
declare -r -i save_stdout=9
declare -r -i save_pipe=7
eval "exec $save_stdout>&1"
v=$(f)
eval "exec $save_stdout>&-"
echo "in main()"
echo "\$\$[$$]:" >>$log
lsof -a -p $$ -d '^mem,^cwd,^rtd,^txt' >>$log
echo "-$v-"
Here is illustration:
(subshell)
main() ....................
+--------------+ . f() .
| 3r pipe | call f() . +--------------+ .
| 9u "stdout" |----------->| 1w pipe(f) | .
+--------------+ . | 9u "stdout" | .
. +--------------+ .
. | .
. | move pipe(f)
. | .
. v . (subshell)
. +--------------+ . ....................
. | 1w "stdout" | . . f2() .
. | 7w pipe(f) | call f2() . +--------------+ .
. | 9- (closed) |------------>| 1w pipe(f2) | .
. +--------------+ . . | 7w pipe(f) | .
. . . | 9u "stdout" | .
. . . +--------------+ .
. . . | .
. . . | move pipe(f2)
. . . | over pipe(f)
. . . | .
. . . v .
. . . +--------------+ .
. +--------------+ . return . | 1w "stdout" | .
. | 1w "stdout" |<------------| 7w pipe(f2) | .
. | 7w pipe(f) | . . | 9- (closed) | .
. +--------------+ . . +--------------+ .
. | . ....................
. | restore pipe(f)
. | .
. v .
. +--------------+ .
+--------------+ return . | 1w pipe(f) | .
| 1u "stdout" |------------| 7- (closed) | .
+--------------+ . +--------------+ .
....................
And here is log (slightly edited)
# ./t.sh >|./1.tmp
f(): SUBSH=1
f(): $$[4794]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4794 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4794 root 1w REG 8,7 0 1121662 .../1.tmp
t.sh 4794 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4794 root 3r FIFO 0,6 14132 pipe
t.sh 4794 root 9w REG 8,7 0 1121662 .../1.tmp
t.sh 4794 root 255r REG 8,7 2075 1121653 .../t.sh
f(): BASHPID[4796]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4796 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 1w FIFO 0,6 14132 pipe
t.sh 4796 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 9w REG 8,7 0 1121662 .../1.tmp
f(): Before moving pipe somewhere
f(): BASHPID[4796]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4796 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 1w REG 8,7 0 1121662 .../1.tmp
t.sh 4796 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 7w FIFO 0,6 14132 pipe
f(): Before calling f2()
f2(): SUBSH=2
f2(): BASHPID[4803]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4803 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4803 root 1w FIFO 0,6 14194 pipe
t.sh 4803 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4803 root 7w FIFO 0,6 14132 pipe
t.sh 4803 root 9w REG 8,7 19 1121662 .../1.tmp
f2(): Before moving pipe somewhere
f2(): BASHPID[4803]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4803 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4803 root 1w REG 8,7 19 1121662 .../1.tmp
t.sh 4803 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4803 root 7w FIFO 0,6 14194 pipe
f2(): Before exit f2()
f(): BASHPID[4796]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4796 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 1w REG 8,7 61 1121662 .../1.tmp
t.sh 4796 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 7w FIFO 0,6 14132 pipe
f(): Before restoring pipe
f(): BASHPID[4796]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4796 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4796 root 1w FIFO 0,6 14132 pipe
t.sh 4796 root 2u CHR 4,1 5466 /dev/vc/1
f(): Before exit f()
$$[4794]:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
t.sh 4794 root 0u CHR 4,1 5466 /dev/vc/1
t.sh 4794 root 1w REG 8,7 71 1121662 .../1.tmp
t.sh 4794 root 2u CHR 4,1 5466 /dev/vc/1
t.sh 4794 root 255r REG 8,7 2075 1121653 .../t.sh
DISCLAIMER. English language used here only for compatibility (ASCII only), so any suggestions about my bad grammar (and not only it) will be greatly appreciated.
четверг, 30 сентября 2010 г.
[draft][part] Shell I/O redirection
DISCLAIMER. English language used here only for compatibility (ASCII only), so any suggestions about my bad grammar (and not only it) will be greatly appreciated.
четверг, 20 мая 2010 г.
[summary][draft][part] Tabs in vim
DISCLAIMER. English language used here only for compatibility (ASCII only), so any suggestions about my bad grammar (and not only it) will be greatly appreciated.
Status: summary.
State: draft,part.
Detailed description: Some tables for illustrate <Tab>'s handling in vim. See vim help for details.
Status: summary.
State: draft,part.
Detailed description: Some tables for illustrate <Tab>'s handling in vim. See vim help for details.
Tabs in vim {{{
'sts' and 'sta' options {{{
Following options affect <Tab>s and indents:
'tabstop' 'ts'
'shiftwidth' 'sw'
'softtabstop' 'sts'
'smarttab' 'sta'
'expandtab' 'et'
'sw' and 'ts' define standard vim operations behavior, they are not
switches for some features (hence they're always set and always used).
But 'sts' and 'sta' enables additional features, which affect (change)
some vim operations behavior (hence, they can be unset to turn feature
off).
Table below shows what option will be used to determine how many
positions insert or delete during some editing operations depending on
activated modes: both 'sts' and 'sta' are off (default), 'sts' set,
'sta' set and both 'sts' and 'sta' set. When editing operation insert
less (or more) positions, than real <Tab> counts for, mix from spaces
and real <Tab>s are used.
+--------------------------+-------------------------------------------+
| Operation | Will be inserted .. positions |
| +------+-----------+-----------+------------+
| | | +sts | +sta | +sts +sta |
+--------------------------+------+-----------+-----------+------------+
| Use >> , etc | sw | sw | sw | sw |
+--------------------------+------+-----------+-----------+------------+
| Type <Tab> or <BS> | ts | sts (mix) | | |
| + + +-----------+------------+
| at the start of line | | | sw (mix) | sw (mix) |
| + + +-----------+------------+
| in other places | | | ts | sts (mix) |
+--------------------------+------+-----------+-----------+------------+
| Real <Tab> length | ts | ts | ts | ts |
+--------------------------+------+-----------+-----------+------------+
}}}
':retab' and changing 'ts' option value {{{
'ts' option changes real tabstop, but does not change text. Hence,
indents, which made according to old tabstop, probably will be messed
(i.e there will be visible changes in text), but actual file remains
untouched. So, using 'undo' after changing 'ts' has no sense.
:retab command changes both 'ts' option and text according to new 'ts'
value in such way, that all indents remain the same (there will be no
visible changes), though actual file will be changed (to preserve
visible indents :retab pads them, if necessary, with spaces). So,
using 'undo' after :retab recover text to previous state, but not
recover 'ts' to previous value, hence indents may be messed (like
after you change only 'ts') and to recover visible text state you need
set 'ts' to previous value. Table below summarizes that.
+-------------------+---------------+-----------+
| | Change 'ts' | :retab |
+-------------------+---------------+-----------+
| 'ts' changed? | yes | yes |
+-------------------+---------------+-----------+
| File changed? | no | yes |
+-------------------+---------------+-----------+
| Visible changes? | yes | no |
+-------------------+---------------+-----------+
}}}
}}}
вторник, 4 мая 2010 г.
[method][draft][part][need_check] (bash) passing arguments to function
DISCLAIMER. English language used here only for compatibility (ASCII only), so any suggestions about my bad grammar (and not only it) will be greatly appreciated.
Status: method.
State: suggestion,draft,part,need_check.
Detailed description: One more method for passing arguments to bash function.
Outline: below under 'passing argument as pointer' i mean passing argument by name:
Status: method.
State: suggestion,draft,part,need_check.
Detailed description: One more method for passing arguments to bash function.
Outline: below under 'passing argument as pointer' i mean passing argument by name:
function f() {
}
declare var='abc'
f var # not f "$var"
This may be considered as analogy for pointers (in C), i think :-)1. Passing argument as pointer to function sometimes may require redefinition
it as local variable in order to preserve referred data. Though, generally
pointer used to provide to function ability to modify caller's environment,
in bash it may be used, to skip unnecessary copying of big argument, if we
want to redefine all positional parameters to local variables (names
1, 2, 3,.. is bad whenever, and also positional parameters may be used for
some tricks, so it's better, when they do not contain useful data).
eval "
$(declare -p $2 | sed -e's/^[^=]\+=/local -a shortopts=/' );
$(declare -p $3 | sed -e's/^[^=]\+=/local -a longopts=/');
"
Above construction is, seemingly, the only way. To correctly redefine
pointer to local variable we should honour several contraints:
1. we should not define any local variable before all pointers will be
expanded, because otherwise there is a chance, that defined local
variable name is match with some pointed to variable's name and we
lose access to it.
2. we should preserve all special characters inside pointed data.
To handle first constraint, we need `eval`.
To handle second, we should properly quote expanded pointed to variable's
value:
${[@]} - split elements correctly only during first expand, but in the
second (done in `eval`) these boundaries will be lost and bash splits
elements by 'metacharacters', not by IFS or anything else (info bash,
ch-2).
${[*]} - my be used, perhaps, with IFS=',', and then.. something
artificial to set up quoting by brace expansion. But this rarely works,
though (i don't know working example).
`declare` - seems, only way to obtain correct quoting without many
evals and artificial tricks. But its output, perhaps, should be
processed by some program to replace variable name to desired one.
[summary][draft][part] Bash script parsing
DISCLAIMER. English language used here only for compatibility (ASCII only), so any suggestions about my bad grammar (and not only it) will be greatly appreciated.
Status: summary.
State: draft,part.
Detailed description: illustration for info bash ch-2.
Status: summary.
State: draft,part.
Detailed description: illustration for info bash ch-2.
Bash script parsing units:
token = single unit
/ \
/ \
/ \
/ \
word operator
/ | \ / \
/ | \ / \
/ | \ / \
reserved name .. control redirection
word operator operator
metacharacter - separate words (or tokens?)
/ \
/ \
/ \
blank some (why not all?)
control operators
пятница, 23 апреля 2010 г.
[additions][done][unmaintained] Дополнение к инструкции по рациям Joker/Kenwood TK/JK-450S.
Status: additions.
State: done,unmaintained.
Detailed description: ...
TODO: [dropped] про набор номера канала.
TODO: [dropped] что включает функция F+0 ?
State: done,unmaintained.
Detailed description: ...
TODO: [dropped] про набор номера канала.
TODO: [dropped] что включает функция F+0 ?
Таблица настроек субтонов CTCSS/DCS.
+-----------------------+--------------------------------------+
| Действие | Настройка |
| +------------------+-------------------+
| | CTCSS | DCS |
+-----------------------+------------------+-------------------+
| Вкл/выкл CTCSS/DCS | (20) CT.DCS |
+-----------------------+--------+---------+---------+---------+
| Уст. тон приема | (7) RC | (21) CT | (9) RD | (22) DC |
+-----------------------+--------+ +---------+ |
| Уст. тон передачи | (8) TC | | (10) TD | |
+-----------------------+--------+---------+---------+---------+
Примечания.
1. настройки (21) CT и (22) DC устанавливают и тон приема, и
тон передачи в одинаковые значения. Поэтому, если тон
приема и передачи будут одинаковые, то ими пользоваться
удобнее, чем двумя разными настройками (7)/(8) или
(9)/(10).
Настройка разных субтонов на прием/передачу и сдвиг частот приема/передачи.
Сдвиг (как частот, так и субтонов) будет работать только при разговоре
двух раций: третья (R-3) рация сможет либо общаться только с первой
(R-1), либо только со второй (R-2). Для разговора c первой надо
настроить третью, как вторую (см. схему ниже). В этом случае, третья
не будет слышать вторую, а вторая не будет слышать третью. Для
разговора со второй надо настроить третью, как первую.
+-----------------------+
v |
Rx +--------------------> Rx
[Ch=B, DCS=Ab] | | [Ch=A, DCS=Ad]
+-----+ | | +-----+
| R-1 | Tx ------+ +------ Tx | R-2 |
| | [Ch=A, DCS=Ad] [Ch=B, DCS=Ab] | |
+-----+ +-----+
Обозначения:
Ch - канал (частота);
DCS - тон DCS;
Последовательность настройки:
A=433.265, Ad=025I, B=433.255, Bd=023N
1. Настраиваем рации на частоту приема.
R-1: ставим частоту 433.255;
R-2: ставим частоту 433.265;
2. Установить сдвиг частот.
R-1: (6) OFFSET ставим на 0.010;
R-2: (6) OFFSET ставим на 0.010;
3. Включить сдвиг частот.
R-1: (5) SFT ставим на '+';
R-2: (5) SFT ставим на '-';
Сдвиг частот включен. Проверяем, что связь между рациями
работает.
4. Настраиваем DCS тон передачи.
R-1: (10) Td ставим на '025I';
R-2: (10) Td ставим на '023N';
5. Настраиваем DCS тон приема.
R-1: (9) Rd ставим на '023N';
R-2: (9) Rd ставим на '025I';
6. Включаем использование DCS тонов.
R-1: (20) CT.DCS ставим на 'DCS';
R-2: (20) CT.DCS ставим на 'DCS';
DCS тона включены. Проверяем, что связь между рациями
работает.
Режимы сканирование:
(1) SCAN= TO - остановка на найденном сигнале и продолжение
через 5 секунд;
CO - остановка на найденном сигнале и продолжение через 5
секунд после пропадания сигнала;
SE - остановка на первом найденном сигнале;
Другие настройки:
(2) TOT - Tx timeout Timer
время (в секундах), после которого передача отключится даже
при нажатой PTT (на случай залипшей PTT).
(11) APO - Automatic Power-off
автоматическое отключение рации через заданное время (в
минутах).
В этой заметке использованы материалы с форумов
tucson-club.ru (tucson-club.ru/forum/...)
и
lpd.radioscanner.ru (lpd.radioscanner.ru/topic...).
Подписаться на:
Сообщения (Atom)
