Nov
25
C/C++标准里头都没有正则表达式,C++还好,可以用上boost::regex,C的话,最简单的还是用系统自带的正则库了。
这个正则库真是相当简单,如果不关心内部琐碎的细节,实际上它只有2个类型、4个函数和7个常量,详细的后面会列出来(或者直接man regex),这里还是直接看例子比较实在:
代码1:email格式检测
这个正则库真是相当简单,如果不关心内部琐碎的细节,实际上它只有2个类型、4个函数和7个常量,详细的后面会列出来(或者直接man regex),这里还是直接看例子比较实在:
代码1:email格式检测
#include <stdio.h>
#include <regex.h>
#include <assert.h>
int main() {
//分配一个regex_t
regex_t reg;
//编译(使用POSIX扩展模式、并忽略大小写),确认编译成功(返回0)
assert(regcomp(®, "^[a-z0-9_]+@([a-z0-9-]+\\.)+[a-z0-9]+$", REG_EXTENDED | REG_ICASE) == 0);
int ret = regexec(®, "steve@rim.jobs", 0, NULL, 0); //执行搜索
//看看返回值:0表示匹配成功,1表示REG_NOMATCH
printf("ret = %d, nomatch = %d\n", ret, REG_NOMATCH);
regfree(®); //记得释放空间
}
#include <regex.h>
#include <assert.h>
int main() {
//分配一个regex_t
regex_t reg;
//编译(使用POSIX扩展模式、并忽略大小写),确认编译成功(返回0)
assert(regcomp(®, "^[a-z0-9_]+@([a-z0-9-]+\\.)+[a-z0-9]+$", REG_EXTENDED | REG_ICASE) == 0);
int ret = regexec(®, "steve@rim.jobs", 0, NULL, 0); //执行搜索
//看看返回值:0表示匹配成功,1表示REG_NOMATCH
printf("ret = %d, nomatch = %d\n", ret, REG_NOMATCH);
regfree(®); //记得释放空间
}
Nov
9
当主机内存想要回收一些虚拟机的内存时,应该怎么办?根据主机OS记录的内存使用情况来swap虚拟机占用的内存吗?不是的。
因为只有虚拟机的OS知道哪些内存是它最需要的,所以让它自己释放内存才是最好的选择。
怎么让它自己释放内存呢?对虚拟机比较了解的同学应该知道气球驱动(Balloon Driver)。其实原理很简单,就是在虚拟机里,使用一个进程申请并占用*一批内存,于是虚拟机的OS便会把它最不需要的内存释放掉一部分。然后这个进程再告诉主机OS我拿到这么多空间啦,你拿去用吧。
*注:申请内存和占用内存通常是两回事。实际上每次调用malloc(其实关键是brk系统调用)等函数分配内存时,系统只是在页表中标记,某些页已经分配给进程XXX,但是对应的地址空间并不是可用的。当进程使用到这个页的时候,会产生一个缺页中断,在中断例程中,系统才会真的从可用空间中分配一个页,然后再让进程继续使用。这个过程对于进程而言是透明的(不过可能会有一些延迟)。这种延迟机制在OS中大量使用,被实践证明是相当有效的,所以有拖延症的同学们,不要太担心哟,适当的拖延不见得是坏事。
说了这么多废话,其实没到这篇的主题。
最近觉得公司配的台式机内存不够了(4G),由于我经常开大量的程序和网页,直到内存不够用的时候才关(拖延。。),因此常常是开个虚拟机的时候空闲内存立刻下降到0,这时候各种卡顿,连鼠标都卡。于是自费在X东上买了一条南亚易胜的 4GB DDR3 1600(这个牌子最便宜。。据说这个牌子给许多其他品牌代工)。安装上去以后,内存不够的现象显著缓解,一口气开三个虚拟机,腰不酸腿不痛的。
但是才用了两天,又发现空闲内存*不多了,经常是才剩下几百MB,有时竟然只有几十MB。虽然任务管理器里说了,8G内存中有6G+是“已缓存”,但是还是怀疑是不是某个进程占用了太多内存。于是一个一个截,全都截掉,空闲内存也还是不到2GB。
*注:Win7任务管理器中的”空闲内存“是malloc以来马上就可以给分配的。“已缓存”是操作系统用内存来保存硬盘上的数据(因为硬盘太慢了)。“可用内存”包括了空闲内存和已缓存。当进程申请的内存超过空闲内存的大小后,OS可以将已缓存的一部分释放掉,但是这个过程需要占用一段时间,效率不如直接使用空闲内存。
于是写了个气球程序来测试。最初的程序很简单,就是while(1)死循环,申请4M内存,然后memset清零。编译,运行,梆!出错了。看了下,进程只申请了2G的内存就出错了,简单分析就知道了,因为我用的是mingw32,生成的32位程序只能申请最多2G的用户空间,再一次malloc的时候,返回的是NULL,于是memset就会导致非法内存访问。
解决办法很简单…………跑3个,然后就申请并占用了6G内存,结束掉之后,发现任务管理器中的已缓存只剩一点点,空闲内存有了6G+,效果显著。看来的确是都被缓存了,不是某个进程太坑爹。注意:如果多跑了一个,就会发现第四个进程速度显著变慢,甚至拖累系统变得相当相当慢,说明这个时候已经在使用swap(或者叫交换空间,虚拟内存,pagefile,页面文件,分页文件……)了,所以不得不慢。
当然,更好的解决方法是编译生成一个64位的可执行程序,这样就能够申请足够多的空间了。到mingw64去下载一个rubenvb编译好的gcc套装直接编译,或者安装个visual studio,都行。
实际上,让系统放弃所有的缓存并不是好事。在XP以及更早的windows系统中,大概是开发人员假设用户的内存总是不够用的,所以系统不会大量使用内存来进行缓存。所以在内存大降价而vista/win7还没出来的时候(大概是08~09年),在XP机器上看到1~2G甚至更多内存并不奇怪,用不完怎么办呢?RAMDISK大行其道,虚拟一个分区出来,速度快得不行。XP的继任者Vista和Win7效仿Unix/Linux系的做法,尽量将内存用于缓存,在很多情况下都可以通过避免磁盘IO来提高系统的反应速度。
因此这里给出个最终版本,默认只回收2G的缓存,再怎么样,缓存3~4G的数据应该已经足够应付日常应用了。
因为只有虚拟机的OS知道哪些内存是它最需要的,所以让它自己释放内存才是最好的选择。
怎么让它自己释放内存呢?对虚拟机比较了解的同学应该知道气球驱动(Balloon Driver)。其实原理很简单,就是在虚拟机里,使用一个进程申请并占用*一批内存,于是虚拟机的OS便会把它最不需要的内存释放掉一部分。然后这个进程再告诉主机OS我拿到这么多空间啦,你拿去用吧。
*注:申请内存和占用内存通常是两回事。实际上每次调用malloc(其实关键是brk系统调用)等函数分配内存时,系统只是在页表中标记,某些页已经分配给进程XXX,但是对应的地址空间并不是可用的。当进程使用到这个页的时候,会产生一个缺页中断,在中断例程中,系统才会真的从可用空间中分配一个页,然后再让进程继续使用。这个过程对于进程而言是透明的(不过可能会有一些延迟)。这种延迟机制在OS中大量使用,被实践证明是相当有效的,所以有拖延症的同学们,不要太担心哟,适当的拖延不见得是坏事。
说了这么多废话,其实没到这篇的主题。
最近觉得公司配的台式机内存不够了(4G),由于我经常开大量的程序和网页,直到内存不够用的时候才关(拖延。。),因此常常是开个虚拟机的时候空闲内存立刻下降到0,这时候各种卡顿,连鼠标都卡。于是自费在X东上买了一条南亚易胜的 4GB DDR3 1600(这个牌子最便宜。。据说这个牌子给许多其他品牌代工)。安装上去以后,内存不够的现象显著缓解,一口气开三个虚拟机,腰不酸腿不痛的。
但是才用了两天,又发现空闲内存*不多了,经常是才剩下几百MB,有时竟然只有几十MB。虽然任务管理器里说了,8G内存中有6G+是“已缓存”,但是还是怀疑是不是某个进程占用了太多内存。于是一个一个截,全都截掉,空闲内存也还是不到2GB。
*注:Win7任务管理器中的”空闲内存“是malloc以来马上就可以给分配的。“已缓存”是操作系统用内存来保存硬盘上的数据(因为硬盘太慢了)。“可用内存”包括了空闲内存和已缓存。当进程申请的内存超过空闲内存的大小后,OS可以将已缓存的一部分释放掉,但是这个过程需要占用一段时间,效率不如直接使用空闲内存。
于是写了个气球程序来测试。最初的程序很简单,就是while(1)死循环,申请4M内存,然后memset清零。编译,运行,梆!出错了。看了下,进程只申请了2G的内存就出错了,简单分析就知道了,因为我用的是mingw32,生成的32位程序只能申请最多2G的用户空间,再一次malloc的时候,返回的是NULL,于是memset就会导致非法内存访问。
解决办法很简单…………跑3个,然后就申请并占用了6G内存,结束掉之后,发现任务管理器中的已缓存只剩一点点,空闲内存有了6G+,效果显著。看来的确是都被缓存了,不是某个进程太坑爹。注意:如果多跑了一个,就会发现第四个进程速度显著变慢,甚至拖累系统变得相当相当慢,说明这个时候已经在使用swap(或者叫交换空间,虚拟内存,pagefile,页面文件,分页文件……)了,所以不得不慢。
当然,更好的解决方法是编译生成一个64位的可执行程序,这样就能够申请足够多的空间了。到mingw64去下载一个rubenvb编译好的gcc套装直接编译,或者安装个visual studio,都行。
实际上,让系统放弃所有的缓存并不是好事。在XP以及更早的windows系统中,大概是开发人员假设用户的内存总是不够用的,所以系统不会大量使用内存来进行缓存。所以在内存大降价而vista/win7还没出来的时候(大概是08~09年),在XP机器上看到1~2G甚至更多内存并不奇怪,用不完怎么办呢?RAMDISK大行其道,虚拟一个分区出来,速度快得不行。XP的继任者Vista和Win7效仿Unix/Linux系的做法,尽量将内存用于缓存,在很多情况下都可以通过避免磁盘IO来提高系统的反应速度。
因此这里给出个最终版本,默认只回收2G的缓存,再怎么样,缓存3~4G的数据应该已经足够应付日常应用了。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int block = 1024 * 1024 * 8; //8M
int main(int argc, char *argv[])
{
int i = 0, reclaim = 2048;
if (argc > 1)
sscanf(argv[1], "%d", &reclaim);
for (i = 0; i < reclaim; i += 8)
{
char *c = (char *)malloc(block);
if (c == NULL)
return 0;
memset(c, 0, block);
printf("%4d MB\n", i);
}
return 0;
}
#include <stdlib.h>
#include <string.h>
const int block = 1024 * 1024 * 8; //8M
int main(int argc, char *argv[])
{
int i = 0, reclaim = 2048;
if (argc > 1)
sscanf(argv[1], "%d", &reclaim);
for (i = 0; i < reclaim; i += 8)
{
char *c = (char *)malloc(block);
if (c == NULL)
return 0;
memset(c, 0, block);
printf("%4d MB\n", i);
}
return 0;
}
Oct
31
在shell里头,有些程序(比如ssh)的交互是从pty中读取的数据,直接的重定向无法解决,因此需要用到expect这种东西。不过这货的编译比较麻烦,各种依赖。幸好有个pexpect是纯python的,存档留个记录。
如果密码错误的话,输出
如果正确,则输出
#!/usr/bin/python
import sys
import pexpect
password = 'password'
expect_list = ['(yes/no)', 'password:']
p = pexpect.spawn('ssh username@localhost ls')
try:
while True:
idx = p.expect(expect_list)
print p.before + expect_list[idx],
if idx == 0:
print "yes"
p.sendline('yes')
elif idx == 1:
print password
p.sendline(password)
except pexpect.TIMEOUT:
print >>sys.stderr, 'timeout'
except pexpect.EOF:
print p.before
import sys
import pexpect
password = 'password'
expect_list = ['(yes/no)', 'password:']
p = pexpect.spawn('ssh username@localhost ls')
try:
while True:
idx = p.expect(expect_list)
print p.before + expect_list[idx],
if idx == 0:
print "yes"
p.sendline('yes')
elif idx == 1:
print password
p.sendline(password)
except pexpect.TIMEOUT:
print >>sys.stderr, 'timeout'
except pexpect.EOF:
print p.before
如果密码错误的话,输出
引用
The authenticity of host 'localhost (127.0.0.1)' can't be established.
RSA key fingerprint is fe:00:00::00:00:00:00:00:00:00:00:00:00:00:00.
Are you sure you want to continue connecting ((yes/no) yes
)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
username@localhost's password: password
Permission denied, please try again.
username@localhost's password: password
Permission denied, please try again.
username@localhost's password: password
Permission denied (publickey,gssapi-with-mic,password).
RSA key fingerprint is fe:00:00::00:00:00:00:00:00:00:00:00:00:00:00.
Are you sure you want to continue connecting ((yes/no) yes
)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
username@localhost's password: password
Permission denied, please try again.
username@localhost's password: password
Permission denied, please try again.
username@localhost's password: password
Permission denied (publickey,gssapi-with-mic,password).
如果正确,则输出
引用
username@localhost's password: password
a
b
bin
code
a
b
bin
code
Oct
30
比赛的起因是这样的,@Tranch同学在SegmentFault.com提了个问题,求一个代码,可以列出字符串"qwerty"被 "." 分割的所有情况,比如 q.werty qwe.rty q.w.e.r.t.y 等等。
这个问题其实很简单,qwerty中间最多可以塞5个". ",每个地方用1表示塞,0表示不塞,也就是正好循环 2^5 次就行了(对于全0的情况不做特别要求,可有可无),实现起来也非常容易,这里是写这篇文章时补充的一个C语言实现:
不过当时没想写这样的代码,而是特意脑抽用python写了个递归的版本:
因为前一段时间看到 这里用21行python代码实现了一个拼写检查器,于是一时兴起,简化成了这个等价但是更难读的版本:
虽然已经很短了,但是我还是想知道,是否有更简单些的实现(一定程度上可以忽略效率和可读性),于是在MSTC的群里发了这个问题,简单起见,把字符串改成了"abcde",问问有没有更短的代码来给出各种组合。
然后 @杭神 扔了个代码出来,被喷“能不能用人话”。这段代码看起来是有些费解,主要思路是,生成 ['****', '***.', '**..', '*...', '....'] 的各种排列,然后用zip('abcd', p)交错组合起来(再删掉'*'):
然后 @霄妹纸 说,实际上那个是笛卡尔积。于是用上itertools.product,再改善下语法,可以写成这样,看起来就清晰多了:
@霄妹纸 还给出了另外两个奇葩的代码,一个是 C 的,充分利用和宏、main函数的参数和递归:
另一个是ruby的:
由于不懂ruby语法,所以这个代码我也只能勉强看看,不过思路上跟上面的python代码是一样的,使用笛卡尔积生成组合序列,然后再与'abcde'交错组合。
结果是,ruby赢了(58个字节),python紧随其后(80字节,不包括import),C语言则意外地以106个字节的代码实现了这个目标。
这个问题从实践的角度上来说没有太大意义,不过可以对比下,不同的语言(C/Ruby/Python)、不同的编程范型(过程式/函数式)的表达方式,一窥函数式编程的魅力~
这个问题其实很简单,qwerty中间最多可以塞5个". ",每个地方用1表示塞,0表示不塞,也就是正好循环 2^5 次就行了(对于全0的情况不做特别要求,可有可无),实现起来也非常容易,这里是写这篇文章时补充的一个C语言实现:
#include <stdio.h>
int main()
{
char str[] = "qwerty";
int i, j;
for (i = 0; i < (1<<5); i++)
{
for (j = 0; j < 5; j++)
{
putchar(str[j]);
if (((i >> j) & 1) == 1)
putchar('.');
}
printf("y\n");
}
return 0;
}
int main()
{
char str[] = "qwerty";
int i, j;
for (i = 0; i < (1<<5); i++)
{
for (j = 0; j < 5; j++)
{
putchar(str[j]);
if (((i >> j) & 1) == 1)
putchar('.');
}
printf("y\n");
}
return 0;
}
不过当时没想写这样的代码,而是特意脑抽用python写了个递归的版本:
def add_dots_l(str):
ret = []
for i in range(1, len(str)):
left = str[:i]
right = str[i:]
ret.append(left + '.' + right)
ret += [j + '.' + right for j in add_dots_l(left)]
ret += [left + '.' + j for j in add_dots_l(right)]
return set(ret)
ret = []
for i in range(1, len(str)):
left = str[:i]
right = str[i:]
ret.append(left + '.' + right)
ret += [j + '.' + right for j in add_dots_l(left)]
ret += [left + '.' + j for j in add_dots_l(right)]
return set(ret)
因为前一段时间看到 这里用21行python代码实现了一个拼写检查器,于是一时兴起,简化成了这个等价但是更难读的版本:
def add_dots(s):
r = [s[:i] + '.' + s[i:] for i in range(1, len(s))]
r += [j + '.' + s[i:] for i in range(1, len(s)) for j in add_dots(s[:i])]
r += [s[:i] + '.' + j for i in range(1, len(s)) for j in add_dots(s[i:])]
return set(r)
r = [s[:i] + '.' + s[i:] for i in range(1, len(s))]
r += [j + '.' + s[i:] for i in range(1, len(s)) for j in add_dots(s[:i])]
r += [s[:i] + '.' + j for i in range(1, len(s)) for j in add_dots(s[i:])]
return set(r)
虽然已经很短了,但是我还是想知道,是否有更简单些的实现(一定程度上可以忽略效率和可读性),于是在MSTC的群里发了这个问题,简单起见,把字符串改成了"abcde",问问有没有更短的代码来给出各种组合。
然后 @杭神 扔了个代码出来,被喷“能不能用人话”。这段代码看起来是有些费解,主要思路是,生成 ['****', '***.', '**..', '*...', '....'] 的各种排列,然后用zip('abcd', p)交错组合起来(再删掉'*'):
from itertools import permutations as p #itertools.permutations是python2.6引入的
map(lambda p: ''.join(j for i in zip('abcd', p) for j in i).replace('*', '') + 'e', [''.join(y) for x in map(lambda i: set(p('*' * (4-i) + '.' * i)), range(5)) for y in x])
map(lambda p: ''.join(j for i in zip('abcd', p) for j in i).replace('*', '') + 'e', [''.join(y) for x in map(lambda i: set(p('*' * (4-i) + '.' * i)), range(5)) for y in x])
然后 @霄妹纸 说,实际上那个是笛卡尔积。于是用上itertools.product,再改善下语法,可以写成这样,看起来就清晰多了:
from itertools import product #itertools.product也是2.6引入的
map(lambda p: ''.join(i + j for i, j in zip('abcd', p)) + 'e', product(['.', ''], repeat = 4))
map(lambda p: ''.join(i + j for i, j in zip('abcd', p)) + 'e', product(['.', ''], repeat = 4))
@霄妹纸 还给出了另外两个奇葩的代码,一个是 C 的,充分利用和宏、main函数的参数和递归:
#define z(a,b) printf(#a"%s",(x>>b)&1?".":""),
main(x){z(a,3)z(b,2)z(c,1)z(d,0)puts("e");16-x&&main(x+1);}
main(x){z(a,3)z(b,2)z(c,1)z(d,0)puts("e");16-x&&main(x+1);}
另一个是ruby的:
p ("b".."e").inject(["a"]){|a,q|a.product [q,"."+q]}.map &:join
如果是ruby 1.9+的话,还可以再少几个字符:p (?b..?e).inject([?a]){|a,q|a.product [q,?.+q]}.map&:join
由于不懂ruby语法,所以这个代码我也只能勉强看看,不过思路上跟上面的python代码是一样的,使用笛卡尔积生成组合序列,然后再与'abcde'交错组合。
结果是,ruby赢了(58个字节),python紧随其后(80字节,不包括import),C语言则意外地以106个字节的代码实现了这个目标。
这个问题从实践的角度上来说没有太大意义,不过可以对比下,不同的语言(C/Ruby/Python)、不同的编程范型(过程式/函数式)的表达方式,一窥函数式编程的魅力~
Oct
23
用Google的第一大烦恼是随时被墙。
番羽土啬吧。
用Google的第二大烦恼是,点击的链接总要过一道Google的统计。比如搜索test,第一条是www.test.com,但是点击的时候,打开的页面是
http://www.google.com.hk/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&ved=0CCoQFjAA&url=http%3A%2F%2Fwww.test.com%2F&ei=LHuGUMSUDKf-iAeg7YCAAg&usg=AFQjCNH21KLjC0CBkjon2DwD_CZ0HApLMw
经常发生的事情是,一直卡在这个链接上,不管是否番羽土啬,反正总是跳不过去;而大部分情况下,目标网页不需要番羽土啬也是可以顺利打开的。
至于Google呢,他才不管你是不是总卡死在这个链接,反正他们要的是你这次点击的数据。
这个问题,可以借助一个叫"Don't Track Me Google"的grease monkey脚本来实现:
http://userscripts.org/scripts/show/121923
对于Firefox,需要安装Grease Monkey插件,而Chrome用户则方便了,直接可以作为插件使用。
页面右上方有个不起眼的 Install 按钮,点一下,会下载一个 xxxx.user.js ,旧版本的chrome就直接当插件安装上去了,新版本的会提示你,不能这么安装非官方来源的插件。解决方法是:打开扩展管理页面,把这个 js 文件拖进去,会问你是否要安装,点击“添加”,done。
番羽土啬吧。
用Google的第二大烦恼是,点击的链接总要过一道Google的统计。比如搜索test,第一条是www.test.com,但是点击的时候,打开的页面是
http://www.google.com.hk/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&ved=0CCoQFjAA&url=http%3A%2F%2Fwww.test.com%2F&ei=LHuGUMSUDKf-iAeg7YCAAg&usg=AFQjCNH21KLjC0CBkjon2DwD_CZ0HApLMw
经常发生的事情是,一直卡在这个链接上,不管是否番羽土啬,反正总是跳不过去;而大部分情况下,目标网页不需要番羽土啬也是可以顺利打开的。
至于Google呢,他才不管你是不是总卡死在这个链接,反正他们要的是你这次点击的数据。
这个问题,可以借助一个叫"Don't Track Me Google"的grease monkey脚本来实现:
http://userscripts.org/scripts/show/121923
对于Firefox,需要安装Grease Monkey插件,而Chrome用户则方便了,直接可以作为插件使用。
页面右上方有个不起眼的 Install 按钮,点一下,会下载一个 xxxx.user.js ,旧版本的chrome就直接当插件安装上去了,新版本的会提示你,不能这么安装非官方来源的插件。解决方法是:打开扩展管理页面,把这个 js 文件拖进去,会问你是否要安装,点击“添加”,done。
Oct
19
经常是用vim打开了某个/etc下的文件,使用 :w 保存的时候提示 "E45: 'readonly' option is set (add ! to override)",而 :w! 则提示 "E212: Can't open file for writing"。通常的解决方案是 :q! 然后 sudo !! 再次编辑,然后保存。
虽然挺麻烦,但是一直也就将就用了。今天有人在SegmentFault.com提出了这个问题,于是仔细考虑了下,的确还是有办法实现的:
:%!sudo bash -c "cat > '%'" #为了防止文件名中的空格之类特殊字符,最好在后一个%前后加上引号
:w !sudo tee % #另一个回答给出的这个方法更简洁,出自 http://vim.wikia.com/wiki/Su-write
其实最初的想法是 :%!sudo cat > % ,但是由于权限的问题(vim打开的shell没法清空当前文件),所以还是得请shell进来掺和一脚:先用sudo给shell提权,然后shell再执行cat将stdin的内容输出到%。
p.s. 顺便给不了解 :%! 这个含义的同学普及一下, :!xxx 是执行 xxx 命令, :%!xxx 则是把当前缓冲区的所有内容当成 stdin 去执行 xxx 命令,然后将xxx的stdout再替换当前缓冲区的内容。比较常见的用法是 :%!sort 给文件所有的行排序,然后 :%!uniq 去重。另外%可以用范围来代替(同 :s 命令的范围)。
虽然挺麻烦,但是一直也就将就用了。今天有人在SegmentFault.com提出了这个问题,于是仔细考虑了下,的确还是有办法实现的:
引用
:w !sudo tee % #另一个回答给出的这个方法更简洁,出自 http://vim.wikia.com/wiki/Su-write
其实最初的想法是 :%!sudo cat > % ,但是由于权限的问题(vim打开的shell没法清空当前文件),所以还是得请shell进来掺和一脚:先用sudo给shell提权,然后shell再执行cat将stdin的内容输出到%。
p.s. 顺便给不了解 :%! 这个含义的同学普及一下, :!xxx 是执行 xxx 命令, :%!xxx 则是把当前缓冲区的所有内容当成 stdin 去执行 xxx 命令,然后将xxx的stdout再替换当前缓冲区的内容。比较常见的用法是 :%!sort 给文件所有的行排序,然后 :%!uniq 去重。另外%可以用范围来代替(同 :s 命令的范围)。
Sep
26
尽管 https://dynamic.12306.cn/otsweb 的 jsessionid 有效期是一年,但是如果不几分钟发个请求的话,照样会被T出来。
所以写了这么个小代码,可以每隔一段时间自动“点”一下重新查询按钮。
=== update @ 16:40 ===
其实简单一点,按下F12,在console里面执行这个就行了...
=== OLD ===
所以写了这么个小代码,可以每隔一段时间自动“点”一下重新查询按钮。
用法:在chrome下打开订票页面,按F12,在框架内找个地方把这段代码扔进去,确定,然后在页面上点击多出来Run按钮,这样就会被个30s自动“点击”一次 [重新查询] 按钮。
所以写了这么个小代码,可以每隔一段时间自动“点”一下重新查询按钮。
=== update @ 16:40 ===
其实简单一点,按下F12,在console里面执行这个就行了...
var f=document.getElementById('main'); var btn=f.contentDocument.getElementById('submitQuery'); setInterval("btn.click()", 30000);
=== OLD ===
所以写了这么个小代码,可以每隔一段时间自动“点”一下重新查询按钮。
<div>
<textarea id="code">
var x=setInterval("document.getElementById('submitQuery').click();", 30000);alert(x);
</textarea>
<input type="button" value="run" onclick="javascript:try{eval(document.getElementById('code').value);}catch(e){alert(e);}"/>
</div>
<textarea id="code">
var x=setInterval("document.getElementById('submitQuery').click();", 30000);alert(x);
</textarea>
<input type="button" value="run" onclick="javascript:try{eval(document.getElementById('code').value);}catch(e){alert(e);}"/>
</div>
用法:在chrome下打开订票页面,按F12,在框架内找个地方把这段代码扔进去,确定,然后在页面上点击多出来Run按钮,这样就会被个30s自动“点击”一次 [重新查询] 按钮。
Sep
23