Programming - yanbin's Blog
简单 Shell 编程 FAQ(〇)
# '$' 在这里用于匹配 '$'字符。 sed 's/A $foobar value/foobar/g' foobar.txt
# $ 展开 foobar 这个变量的值。转义的 \$ 匹配 '$'。 # 参数在传递给 sed 程序时已经完成变量值展开和转义了。 # 完成转义和变量展开的是 shell 而不是 sed. sed "s/A $foobar \$value/foobar/g" foobar.txt
# 这个与用 '“'括起来的效果是相同的。 sed s/A $foobar \$value/$/g foobar.txt
# 不熟悉 sed 时一般会写这样的代码。这种方式容易出错且耗费资源。 cat foobar.txt | sed 's/patter to match//gp' > tmp_file.txt mv tm_file.txt foobar.txt
# sed 的 d 命令 加 -i 参数 可以完成直接修改文件的操作。 sed -i '/pattern to match/d' foobar.txt
# 只输未匹配即没有被删除的行,而不修改文件 sed 'pattern to match/d' foobar.txt
edit files in place (makes backup if SUFFIX supplied)
# -i 参数接受一个可选的 suffix, 指定这个 suffix, sed 会修改文件前备份文件 sed -i.bak '/pattern to match/d' foobar.txt
shell 脚本中,程序的标准输出重定向到 FIFO, 需要注意的问题
remain blocked.
shell脚本使用 timeout + wait 完成: 超时退出执行,等待执行完毕并处理执行结果
timeout time sub cmdresp_topic > cmdresp_record while seq in read seqs: seq = parse_seq(seq) message = create_message(seq) pub cmd_topic message record(message, msg_record) // do something, maybe sleep 1s wait sub parse(cmdresp_record, msg_record)
shell 代码是:
Lua 调用的 C 函数保存 state 的两种方式: Storing State in C Functions 笔记
为什么使用 do {} while(0)
有些宏定义含有多行代码,一般使用 do {} while(0) 把代码放在 'do' 和 'while' 之间的 '{}' 中。
#define foorbar(msg, callback) do {\ struct Task __task = msg_to_task((msg)); \ if (__task != NULL) { \ process(__task, (callback)); \ char *__msg = task_to_msg(__task); \ if (__msg != NULL) \ { send_msg(__msg); \ free(__msg); \ } \ destroy_task(__task); \ } while (0)
这样用的原因是:
1.符合 C/C++ 语法习惯。
每条语句后面都一个';', 而 do {} while 语句后面也要加一个 ';'.
2.避免出现语法错误。
不用 do {} while(0) 把多行代码包起来,在 if else 语句中就会有语法错误,例如:
#define foorbar(a, b) foor((a)); bar((b)) if (something) /* 以下有语法错误 */ foorbar(3, 2); else // do something
仅仅使用 '{}' 把多行代码包起来,如果在调用宏之后加 ';', 也会有语法错误。
#define foorbar(a, b) {\ foor((a)); bar((b));\ } foorbar(3, 2); // 此处有语法错误 /* 编译器提示: * error: expected ‘;’ before ‘}’ token * 如果不加 ';', 不会有语法错误但是这样不符合 C/C++ 的语法习惯 */
3.do {} while(0) 可以根据条件跳出执行。
#define foorbar() do {\ struct condition __cond; \ if (__cond.wait_cond()) \ break; // 条件发生退出执行 \ // 条件没有发生 do something } while(0)
4.私以为 do {} while(0) 可以保证代码执行并且只执行一次。
5.需要注意的地方。
(a)宏定义时用 '\' 连接多行语句;
(b)宏定义中定义变量,注意与外部变量名字冲突,不然原本希望用外面的变量,却用了新定义的变量。
(c)有些编译器会优化掉 do {} while(0); 直接展开 '{}' 内的代码, 如(b)所描述,此时会出现语法错误。
FIXME: 如果内部有 'break' 并且 'break' 的执行依赖运行时条件,编译器就不会优化掉 do {} while(0); 了。
举例:
#define foorbar() do {\ struct condition cond; \ if (cond.wait_cond()) \ break; // 条件发生退出执行 \ // 条件没有发生 do something } while(0) struct condition cond; // do something foobar(); // 到底用的是哪一个 cond?
#define foorbar(a, b) do {\ const char *something = get_something(a, b); \ } while(0) const char *something; // do something foorbar(3, 9); // 如果编译器优化掉了 do {} while(0); 这里有语法错误。
感谢 老猫,mike2,MovableType@源赖朝 三位网友。
参考:
do { … } while (0) — what is it good for?
do{}while(0) 的作用
Linux 系统中使用 inotify 监视文件或目录的改变
0.注意事项
int inotify_init();
int inotify_add_watch(int fd, const char *name);
int inotify_rm_watch(int fd, int wd);
int inotify_init1(int mask);
这些是一系列的 linux 系统调用;
前三个是 linux 2.6.13 引入的, 最后一个是 2.6.27 引入的。
但是一些 C libray(C 语言实现库), 并没有定义这些系统调用的封装。
可以用 syscall(__NR_inotify_init); 这样的形式调用。
__NR_inotify_init 是系统调用号,可以在 unistd.h 中看到。
有些 SDK 中的内核配置没有默认的选定对 inotify 的支持。
可以在 linux 配置中的 kernel setup:
fs-->
[] support inotify for user space
选上对些系统调用的支持。
如果内核没有对这些系统调用的支持,
int fd = syscall(inotify_init) 总是返回 89,
read(fd, buff, sizeof(buff)) 会返回 -1, errno 被设置为 "Bad file descriptor"。
inotify 会监视目录下所有文件。
inotify 并不自动的递归监视目录下的子目录,需要程序员自己完成这样的工作。
1.简介
使用这些 API 可以监视文件系统的 events.
当文件或者目录有改变时,内核产生 inotify events, 用户使用这些 API 获取关注的 events.
不同于陈旧的 dnotify API, inotify API 既可以监视 files 也可以监视 directories.
监视一个目录,不仅可以获取目录自身改变的 event(e.g. 从目录移除文件),也可以监视目录内文件内容改变产生的 event.
另外:称这些函数为 API 是因为它封装了 system call。每一个函数对应一个 system call.
读取 /dev/urandom or /dev/random 生成随机数
Regex Unicode 笔记
类型安全的 max(), min()
#define max(a, b) \ ({ __typeof__ (a) (_a) = (a); \ __typeof__ (b) (_b) = (b); \ _a > _b ? _a : _b; }) #define min(a, b) \ ({ __typeof__ (a) (_a) = (a); \ __typeof__ (b) (_b) = (b); \ _a < _b ? _a : _b; })
valgrind 简单使用
自动链接,但是要求有, 如果没有 valgrind 不能正常启动内存检查.
程序用到的其他 C 库也要有 debug 版本的。
也可以使用 gcc 的 -O0 编译选项。据说使用了更好。(大写 O, 数字 0)
-g 是表示编译出的二进制代码中包含调试符号
-O0 是 gcc 的默认选项。可能一些低版本的 gcc 需要加上这个选项。
$ gcc -O0 -g example.c -o example
$ valgrind --leack-check=yes ./example arg1 arg2
下面是一个正常分配并正常释放内存的程序用 valgrind 调试的输出: