蓝色寂静的夜里
我一个人思考哲学
虫儿在草丛中 打滚 鸣叫
叫得很可口的样子
今夜 我不会吃他们的
月亮那么的…圆呀
那么的圆 那么圆
那么的…
比世界任何圆的东西都要圆
比世界任何圆的东西都要圆
广大的广大的 宇宙的某处
还有另一个我吧
和我一样的在草丛中
在弹着吉他吗?
在唱着喵喵的歌吗?
孤独一人是这么的 寂寞啊
这么的 寂寞 这么的…
这个时候大家在做什么呢喵
这个时候大家在做什么呢喵
变得想打电话给其他人了喵
蓝色寂静的夜里
我一个人思考哲学
虫儿在草丛中 打滚 鸣叫
叫得很可口的样子
今夜 我不会吃他们的
月亮那么的…圆呀
那么的圆 那么圆
那么的…
比世界任何圆的东西都要圆
比世界任何圆的东西都要圆
广大的广大的 宇宙的某处
还有另一个我吧
和我一样的在草丛中
在弹着吉他吗?
在唱着喵喵的歌吗?
孤独一人是这么的 寂寞啊
这么的 寂寞 这么的…
这个时候大家在做什么呢喵
这个时候大家在做什么呢喵
变得想打电话给其他人了喵
最近在写shell脚本,主要工作就是解析配置文件,那么学习sed与awk就在所难免了,另外还系统的看了find命令的使用,现在就将这些成果汇总起来,以便今后参考。
awk 是一种编程语言,对文本和数据进行处理,支持正则表达式,突出特点是对文本列的操作。
1 常见操作
awk ‘{print $1,$3}’ tmp.txt
awk –F ‘:’ ‘{print $1”|”$3}’ tmp.txt //以冒号作为域分割符并且输出的分割符为|
2 打印记录
awk ‘BEGIN {print “Begin \n-----------------”}
{print $0}’ tmp.txt //打印头
awk ‘BEGIN {print “Begin \n-----------------”}
{print $0}
END {print” -----------------\nEnd”}’ tmp.txt //打印头尾
3 条件运算符
awk ‘{if ($1~/tomy/) print $0}’ tmp.txt //匹配文本域1为tomy的记录
awk ‘$2==”30” {print $1,”age is 30.”}’ tmp.txt //精确匹配
4 利用正则表达式
awk ‘/[Gg]reen/’ tmp.txt //匹配Green或者green
awk ‘$4~/[Gg]reen/’ tmp.txt
awk ‘$4~/([Gg]reen|[Rr]ed)/’ tmp.txt //或关系匹配
5 使用内置变量
awk ‘{print NF,NR,$0}
END {print FILENAME}’ tmp.txt //NF为列数,NR为行号
6 使用内置字符串函数
awk ‘gsub (/30/,thirty) {print $0}’ tmp.txt //把有30的行中的30改为thirty
awk ‘BEGIN {print split(“123#456#789”,m_array,”#”)}’ //split返回数组m_array的下标数3,m_array取值:m_array[1]为123,m_array[2]为456,m_array[3]为789
7 输出函数printf
awk ‘{printf “%-10s---%s\n”,$1,$3}’ tmp.txt //类似C语言printf函数
sed是非交互文本流编辑器,使用sed可以从文件和字符串中抽取所需信息。
1 打印范围
sed –n ‘1,3p’ sed.txt > sed.tmp
sed –n ‘1,$p’ sed.txt > sed.tmp
2 模式查询
sed –n ‘/should/p’ sed.txt //查找should的行
sed –n ‘/should/=’ sed.txt //输出匹配的行号
3 特殊字符查询
sed –n ‘/\./’p sed.txt //查找有.的行
4 删除文本
sed ‘1,3d’ sed.txt
sed ‘/should/d’ sed.txt
5 替换文本
sed ‘s/PS/ps/’ sed.txt //替换每行第一个匹配
sed ‘s/PS/ps/g’ sed.txt //全文替换
sed ‘1,3 s/should/SHOULD/g’ sed.txt //指定范围替换
sed ‘1 s/should/SHOULD/g’ sed.txt //指定行替换
6 sed脚本文件
6.1 含sed命令的脚本
$ cat append.sed
#!/bin/sed –f
/should/ a\
Just a test.
$ chmod +x append.sed
$ ./append.sed sed.txt
6.2 不含sed命令脚本
$ cat append.sed
/should/ a\
Just a test.
$ chmod +x append.sed
$ sed -f append.sed sed.txt
1 name选项
find ~ -name “*.txt” –print
find . –name “[A-Z]*” –print
2 perm选项
find . –perm 755 -print
3 按更改时间查找
find / -mtime -5 –print //更改时间在五日以内
find / -mtime +3 –print //更改时间在三日之前
4 type选项
find /etc –type d –print //查找/etc目录下所有的目录
find /etc –type l –print //查找/etc目录下所有的符号链接文件
5 使用exec或ok
find . –type f –exec ls –l {} \; //注意{}和\;之间有空格
find . -name “*.log” –mtime +5 -exec rm {} \;
本文主要讨论的是运算符重载中有关++/–(增量和减量)的重载并介绍了前缀后缀应用机制的发展演变。
##运算符重载的基本概念
在c++语言中,可以用关键字operator加上运算符来表示函数,叫做运算符重载。运算符重载函数是一种特殊形式的函数,即运算符本身就是函数名,并且不改变它们作为内置运算符时的使用方法。例如两个复数相加函数:
Complex Add(const Complex& a, const Complex& b);
可以用运算符重载来定义:
Complex operator+(const Complex& a, const Complex& b);
运算符与普通函数在调用时的不同之处在于:对于普通函数,实参出现在圆括号内;而对于运算符,实参出现在其两侧(或一侧)。运算符重载是支持数据抽象和泛型编程的利器。比如一般来说,凡是用作容器元素类型的class(包括struct)都需要重载“=”、“==”和“<”等运算符,因为容器可能会使用它们来排序或者拷贝元素,某些泛型算法都是以假设元素类型已经重载了“=”和“<”为前提的。
##重载++和–
重载++和–这两个运算符之所以令许多人困惑,是因为它们都存在前置版本和后置版本。许多教科书中关于后置版本的语义解释并不完全正确,而在c++程序中,你可能要为某些类重载“++”和“–”运算符,正确理解它们的语义是非常重要的。c++标准规定:当为一个类型重载“++”/“–”的前置版本时,不需要参数;当为一个类型重载“++”/“–”的后置版本时,需要一个int类型的参数作为标志(哑元,非具名参数)。想知道这个哑元的由来么?为什么会是这样,而不是通过一个特殊的关键字来标识这种位置关系,《the design and evolution of c++》中是这样说的:
增量运算符++和减量运算符–都是用户可以定义的运算符,但是release1.0并没有提供区分前缀或后缀应用的机制,于是乎:
class Ptr{
// ...
void operator++();
};
在这两种情况中使用的都是同一个Ptr:operator++():
void f(Ptr& p){
p++; // p.operator++()
++p; // p.operator++()
}
Bjarne收到很多的建议,特别是Brian Kernighan指出,从c语言的观点来看,这种限制是不自然的,它也阻止了人们定义那种能够用来取代常规指针的类。他考虑到了最明显的解决办法,在c++里增加关键字prefix和postfix:
class Ptr_to_X{
// ...
X& operator prefix++(); //prefix ++
X operator postfix++(); //postfix ++
};
或者:
class Ptr_to_X{
// ...
X& prefix operator++(); //prefix ++
X postfix operator++(); //postfix ++
};
这样一来,又有一些人开始叫喊了:“随随便便”增加关键字什么的最讨厌了!人们建议了几个并不涉及新关键字的方案。例如:
class Ptr_to_X{
// ...
X& ++operator(); //prefix ++
X operator++(); //postfix ++
};
或者:
class Ptr_to_X{
// ...
X& operator++(); //prefix because it returns a reference
X operator++(); //postfix because it doesn't return a reference
};
c++之父觉得前一个太做作,而后一个又太微妙(我既没有看出哪个做作也看不出什么微妙,惭愧),最后停止在了这个可能是既做作又微妙的方案上(不一般的思维):
class Ptr_to_X{
// ...
X& operator++(); //prefix: no argument
X operator++(int); //postfix: because of the argument
};
c++设计与演化关于此的原话摘录如下:
This may be both too cute and too subtle, but it works, requires no new syntax, and has a logic to the madness. Other unary operators are prefix and take no arguments when defined as member functions. The “odd” and unused dummy int argument is used to indicate the odd postfix operators. In other words, in the prefix case, ++ comes between the first(real) operand and the second(dummy) argument and is thus postfix.
These explanations are needed because the mechanism is unique and therefore a bit of a wart. Given a choice, I would probably have introduced the prefix and postfix keywords, but that didn’t appear feasible at the time. However, the only really important point is that the mechanism works and can be understood and used by the few programmers who really need it.
最后举一个例子来说明如何重载这两个运算符
class Integer{
public:
Integer(long data):m_data(data){}
Integer& operator++(){ //前置版本,返回引用
cout<<"Integer::operator++() called!"<<endl;
m_data++;
return *this;
}
Integer operator++(int){ //后置版本,返回对象的值
cout<<"Integer::operator++(int) called!"<<endl;
Integer temp = *this;
m_data++;
return temp; //返回this对象的旧值
}
...
private:
long m_data;
};
int main(){
Integer x = 1; //call Integer(long), ?Integer(1)
++x; //call operator++()
x++; //call operator++(int)
return 0;
}
当“++”/“–”应用于基本数据类型时,前置版本和后置版本在效率上没有多大差别。然而,当应用于用户定义类型,尤其是大对象的时候,前置版本就会比后置版本的效率高许多。后置版本总是要创建一个临时对象,在退出函数时还要销毁它,而且返回临时对象的值时还会调用其拷贝构造函数。所以,如果可以选择,请尽量使用前置版本。