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
Sep
3
#!/bin/bash
API=https://dnsapi.cn/Record.Ddns
IP_FILE=/tmp/dnspod_ip
function get_old_ip()
{
ip=
if [ -e "$IP_FILE" ]; then
ip=`cat $IP_FILE`
fi
echo $ip
}
function save_ip()
{
echo -n $1 > $IP_FILE
}
function get_new_ip()
{
echo `nc ns1.dnspod.net 6666`
}
email=帐号邮箱
password=帐号密码 #dnspod就不能搞成个secret_key么!明文密码让人很不舒服啊。
domain_id=XXXXX #使用Domain.List API获取
record_id=YYYYY #使用Record.List API获取
sub_domain="zzz" #DDNS的二级域名
new_ip=`get_new_ip`
old_ip=`get_old_ip`
if [ "$new_ip" != "$old_ip" ];
then
curl $API -d "format=json&login_email=$email&login_password=$password&domain_id=$domain_id&record_id=$record_id&sub_domain=$sub_domain&record_line=默认"
save_ip $new_ip
fi
API=https://dnsapi.cn/Record.Ddns
IP_FILE=/tmp/dnspod_ip
function get_old_ip()
{
ip=
if [ -e "$IP_FILE" ]; then
ip=`cat $IP_FILE`
fi
echo $ip
}
function save_ip()
{
echo -n $1 > $IP_FILE
}
function get_new_ip()
{
echo `nc ns1.dnspod.net 6666`
}
email=帐号邮箱
password=帐号密码 #dnspod就不能搞成个secret_key么!明文密码让人很不舒服啊。
domain_id=XXXXX #使用Domain.List API获取
record_id=YYYYY #使用Record.List API获取
sub_domain="zzz" #DDNS的二级域名
new_ip=`get_new_ip`
old_ip=`get_old_ip`
if [ "$new_ip" != "$old_ip" ];
then
curl $API -d "format=json&login_email=$email&login_password=$password&domain_id=$domain_id&record_id=$record_id&sub_domain=$sub_domain&record_line=默认"
save_ip $new_ip
fi
然后加入crontab,每隔15分钟跑一次进行更新
*/15 * * * * ~/bin/dnspod.sh
Aug
24
:set formatoptions+=m "允许对multi_byte字符换行(否则默认只能空格或者英文标点,详见set breakat=)
:set textwidth=80 "换行的长度
ggVG "选中全文
gq "应用到选中文本
p.s. 最后两句也可以缩写成 gggpG (少一个字符)..
:set textwidth=80 "换行的长度
ggVG "选中全文
gq "应用到选中文本
p.s. 最后两句也可以缩写成 gggpG (少一个字符)..
Aug
22
可能很多同学不知道Windows是自带这个功能的。至少从WinXP开始就有。操作要领:
0. 批量重命名的文件应该在一个文件夹内。
1. 选择所有需要被重命名的文件。全选(CTRL+A),或拖动/用shift选择选择一个区间,或按住CTRL一个一个点,都可以。
2. 使用鼠标右键选择你希望被重命名的第一个文件,输入新的文件名。注意,新的文件名如果不带编号(如a.txt),那么会按顺序改成 a.txt, a (1).txt ... a (5).txt,如果带编号(如 b (3).txt,注意编号只能用圆括号包起来),则编号会按顺序增加:b (3).txt, b (4).txt ... b (11).txt。
3. 回车,OVER。
功能很贴心,但是半残,有时候不满足要求,在没有安装额外的语言的情况下,可以用类似如下的vbs来应急:
0. 批量重命名的文件应该在一个文件夹内。
1. 选择所有需要被重命名的文件。全选(CTRL+A),或拖动/用shift选择选择一个区间,或按住CTRL一个一个点,都可以。
2. 使用鼠标右键选择你希望被重命名的第一个文件,输入新的文件名。注意,新的文件名如果不带编号(如a.txt),那么会按顺序改成 a.txt, a (1).txt ... a (5).txt,如果带编号(如 b (3).txt,注意编号只能用圆括号包起来),则编号会按顺序增加:b (3).txt, b (4).txt ... b (11).txt。
3. 回车,OVER。
功能很贴心,但是半残,有时候不满足要求,在没有安装额外的语言的情况下,可以用类似如下的vbs来应急:
Set a= WScript.createObject("WScript.Shell")
WScript.sleep 1000
For i = 1 to 23
j = i
If i < 10 Then
j = "0" & i
End If
a.sendkeys "{DOWN}{F2}" '向下,F2(重命名)
a.sendkeys "TBBTs02e" & j '文件名, win7下就不用再 & ".rmvb" 了,但是xp需要
a.sendkeys "~" '回车
WScript.sleep 200
Next
WScript.sleep 1000
For i = 1 to 23
j = i
If i < 10 Then
j = "0" & i
End If
a.sendkeys "{DOWN}{F2}" '向下,F2(重命名)
a.sendkeys "TBBTs02e" & j '文件名, win7下就不用再 & ".rmvb" 了,但是xp需要
a.sendkeys "~" '回车
WScript.sleep 200
Next
Aug
21
去年 czyhd同学 推荐的BurstNet的VPS用了正好一年。到上周一之前,总体来说是很满意的,性价比高,带宽和延迟基本满足要求。但是上周一空间突然无法访问了。我以为是偶然的情况(GFW/公司网络封堵/母鸡整修等),但是却收到一封Reseller发来的邮件,说是BurstNet怀疑我利用VPS乱发垃圾邮件,还附上了一份pstree的输出,其中显示smtpd服务启动了32个,要我对此作出解释。
由于对方是万恶的美帝,还要经过日李万基的reseller,所以往来3封邮件花了三天的时间,仍然没有解决问题,怒了,直接在 Ramhost 另外买了个VPS,基于KVM技术,256M RAM + 7GB HDD,$4.99/Month(可以使用paypal转网银以RMB支付)。看起来参数是不如原先安个OpenVZ的512M+20GB(35元/月,买10送2),但是由于Ramhost承诺不超售,因此实际性能(CPU、内存、网络)应该是要超过BurstNet,而价格上也没有太大的差别。
折腾了两三天,目前装上了Ubuntu 12.04 Server x86_64,nginx + php-fpm + mysql, sshd, pptpd, postfix, denyhosts, 稳定运行了一段时间以后,free的输出大约是
总体来说还是比较满意的,实际速度也比原先的vps快,尤其是刷网页的时候很明显。
在安全方面,VPS什么都得自己搞,比较头疼。
denyhosts已经往/etc/hosts.deny里面加入了7个ip,都是试图ssh登录失败多次的。
在邮件方面,这次特别注意了,使用iptables限制只能是本地ip才能连上tcp#25。
iptables -A INPUT -j ACCEPT -p tcp --dport 25 -s 127.0.0.1
iptables -A INPUT -j REJECT -p tcp --dport 25
在web方面,大概分析了下头天的nginx log,发现有大量的异常访问,于是根据UA屏蔽了许多抓站请求(不是常见的Spider)。比较特殊的是被GFW屏蔽的那个 /t ,目前仍有少量请求,而且UA为空,看起来像是GFW的回访,所以果断屏蔽之。
大概就是这样。
p.s. 遇到一件很不靠谱的事情:昨晚Ramhost给我换了个IP,居然没有任何通知!折腾了半天,看到管理面板上的IP有异我才发现,果断发TICKET质问他们,看他们如何解释,艹。
p.p.s. 奇葩解释:"You are mistaken. Your IP address was and has always been 199.180.255.30, Seeing as your account is only 4 days old we have absolutely no reason to need to change your IP address. We have not and will not change your IP address like that." 好吧。怪我没有留下证据。
由于对方是万恶的美帝,还要经过日李万基的reseller,所以往来3封邮件花了三天的时间,仍然没有解决问题,怒了,直接在 Ramhost 另外买了个VPS,基于KVM技术,256M RAM + 7GB HDD,$4.99/Month(可以使用paypal转网银以RMB支付)。看起来参数是不如原先安个OpenVZ的512M+20GB(35元/月,买10送2),但是由于Ramhost承诺不超售,因此实际性能(CPU、内存、网络)应该是要超过BurstNet,而价格上也没有太大的差别。
折腾了两三天,目前装上了Ubuntu 12.04 Server x86_64,nginx + php-fpm + mysql, sshd, pptpd, postfix, denyhosts, 稳定运行了一段时间以后,free的输出大约是
引用
felix021@felix021:~$ free -m
total used free shared buffers cached
Mem: 239 220 19 0 14 133
-/+ buffers/cache: 72 167
Swap: 490 24 466
total used free shared buffers cached
Mem: 239 220 19 0 14 133
-/+ buffers/cache: 72 167
Swap: 490 24 466
总体来说还是比较满意的,实际速度也比原先的vps快,尤其是刷网页的时候很明显。
在安全方面,VPS什么都得自己搞,比较头疼。
denyhosts已经往/etc/hosts.deny里面加入了7个ip,都是试图ssh登录失败多次的。
在邮件方面,这次特别注意了,使用iptables限制只能是本地ip才能连上tcp#25。
iptables -A INPUT -j ACCEPT -p tcp --dport 25 -s 127.0.0.1
iptables -A INPUT -j REJECT -p tcp --dport 25
在web方面,大概分析了下头天的nginx log,发现有大量的异常访问,于是根据UA屏蔽了许多抓站请求(不是常见的Spider)。比较特殊的是被GFW屏蔽的那个 /t ,目前仍有少量请求,而且UA为空,看起来像是GFW的回访,所以果断屏蔽之。
大概就是这样。
p.s. 遇到一件很不靠谱的事情:昨晚Ramhost给我换了个IP,居然没有任何通知!折腾了半天,看到管理面板上的IP有异我才发现,果断发TICKET质问他们,看他们如何解释,艹。
p.p.s. 奇葩解释:"You are mistaken. Your IP address was and has always been 199.180.255.30, Seeing as your account is only 4 days old we have absolutely no reason to need to change your IP address. We have not and will not change your IP address like that." 好吧。怪我没有留下证据。
Aug
17
对ssh用得比较多的同学应该知道通过建立信任关系来免除输入密码的麻烦:
在A机器上执行:
$ ssh-keygen -t rsa (各种回车)
$ ssh-copy-id -i ~/.ssh/id_rsa.pub USER@B_ip
然后在A机器上 ssh USER@B_ip 就可以免密码使用USER用户登录B机器了。
实际上第二步操作是将 A 机器该用户的公钥(id_rsa.pub)追加到B机器的 ~/.ssh/authorized_keys 文件末尾中去。
当A机器访问B时,如果B机器的sshd能够在/home/USER/.ssh/authorized_keys中找到对应的公钥,就认为A机器具有B机器的USER用户访问权限,于是就直接让A机器以USER身份登录。
但是上周在线上某台机器进行操作时却发现这一机制失效了。通过该机制,A=>B可登录,但是B=>A失败,甚至A=>A也失败(B=>B却成功)。虽然问题很奇怪,但说明问题出在A机器上。
首先是 diff 了A、B两台机器的 /etc/ssh ,发现完全相同,所以不是配置的问题。
然后查看 ssh -vv localhost
而在B机器上,we sent a public key packet, wait for reply 之后则是紧跟着"debug1: Server accepts key: pkalg ssh-rsa blen 279"。由此可以看出,是A机器的sshd不认可publickey。
至于为什么不认可,在google上查了许多,毫无头绪,直到使用类似“ssh publickey ignore debug diagnose”这样的关键词,发现这个页面,其中的第二条和第六条给出了解答:
通过执行 /usr/sbin/sshd -d -p 2222 (在2222端口启动一个带debug输出的sshd) ,然后 ssh -vv localhost -p 2222 ,可以看到sshd输出了一行
正好与那第六条相对应,再检查一下 /home/felix021 ,其权限是其他组可写。
最终解决方案:将用户home目录的权限改为0755,登录成功。
在A机器上执行:
$ ssh-keygen -t rsa (各种回车)
$ ssh-copy-id -i ~/.ssh/id_rsa.pub USER@B_ip
然后在A机器上 ssh USER@B_ip 就可以免密码使用USER用户登录B机器了。
实际上第二步操作是将 A 机器该用户的公钥(id_rsa.pub)追加到B机器的 ~/.ssh/authorized_keys 文件末尾中去。
当A机器访问B时,如果B机器的sshd能够在/home/USER/.ssh/authorized_keys中找到对应的公钥,就认为A机器具有B机器的USER用户访问权限,于是就直接让A机器以USER身份登录。
但是上周在线上某台机器进行操作时却发现这一机制失效了。通过该机制,A=>B可登录,但是B=>A失败,甚至A=>A也失败(B=>B却成功)。虽然问题很奇怪,但说明问题出在A机器上。
首先是 diff 了A、B两台机器的 /etc/ssh ,发现完全相同,所以不是配置的问题。
然后查看 ssh -vv localhost
引用
....
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/felix021/.ssh/id_rsa
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/felix021/.ssh/id_dsa
debug1: Trying private key: /home/felix021/.ssh/id_ecdsa
debug2: we did not send a packet, disable method
debug1: Next authentication method: password
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/felix021/.ssh/id_rsa
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/felix021/.ssh/id_dsa
debug1: Trying private key: /home/felix021/.ssh/id_ecdsa
debug2: we did not send a packet, disable method
debug1: Next authentication method: password
而在B机器上,we sent a public key packet, wait for reply 之后则是紧跟着"debug1: Server accepts key: pkalg ssh-rsa blen 279"。由此可以看出,是A机器的sshd不认可publickey。
至于为什么不认可,在google上查了许多,毫无头绪,直到使用类似“ssh publickey ignore debug diagnose”这样的关键词,发现这个页面,其中的第二条和第六条给出了解答:
引用
2. Debugging on the remote host by running sshd in debug mode: Run ‘/usr/sbin/sshd -d -p 2222′ on the remote host and connect to it. ’2222′ here is the port number of the sshd process you started on the remote host.
6. Check the permissions on your home directory, .ssh directory, and the authorized_keys file: If your ssh server is running with ‘StrictModes on’, it will refuse to use your public keys in the ~/.ssh/authorized_keys file. Your home directory should be writable only by you, ~/.ssh should be 700, and authorized_keys should be 600.
6. Check the permissions on your home directory, .ssh directory, and the authorized_keys file: If your ssh server is running with ‘StrictModes on’, it will refuse to use your public keys in the ~/.ssh/authorized_keys file. Your home directory should be writable only by you, ~/.ssh should be 700, and authorized_keys should be 600.
通过执行 /usr/sbin/sshd -d -p 2222 (在2222端口启动一个带debug输出的sshd) ,然后 ssh -vv localhost -p 2222 ,可以看到sshd输出了一行
引用
Authentication refused: bad ownership or modes for directory /home/felix021
正好与那第六条相对应,再检查一下 /home/felix021 ,其权限是其他组可写。
最终解决方案:将用户home目录的权限改为0755,登录成功。