我真的不讨厌GFW,因为现在话语权不在我们的手中,我们必须保护自己。至于外网上 的东西,我们应该有自己的辨别能力。从内容和数量上来说,那些对china不利的网络 言论与对America不利的网络言论,根本不是一个数量级。再一个恶心的是,Youtube, 即便你是单纯的想休闲娱乐,可是不超过三次单击,有关我国的负面新闻铺面而来。 难道国外的领导人真的那么清廉。
如果其他方法暂时无法使用了,先使用最简单的ssh代理,也就是你必须随身携带一个 vps。
无论使用什么浏览器,最根本的一句命令是
ssh -N -D 7070 root@your_ip
首选项->高级->网络->设置
只使用SOCKS那个选项,主机填上127.0.0.1,端口是7070,下面的类型选择SOCKS_v5
-D
选项是socks_v5的含义。
首先安装的话,
sudo apt-get update
apt-get install chromium chromium-l10n
这一个是chrome的测试版本吧,开源的,比较好用的。先用它得了。
但是它不支持Desktop,只能使用命令行,在完成上面的配置后,你可以使用如下command打开chromium
chromium --proxy-server="socks:127.0.0.1:7070"
前面是应急使用的,正常渠道我们应该好的工具。
如果我写得不清晰,接下来请看这篇
但是我还要自己写一下,以免到时用的时候找不到了。
这个可以自己搭建,可以购买。自己搭建的步骤我会完善,现在我的重点是在客户端上。
补充,在自己的vps上搭建ss的服务端,可以使用这个脚本。here
按照下面的命令:
chmod +x shad.....sh
./shad.....sh 2>&1 | tee shad.....log
这篇文章不是从简单的vim操作开始,它只是我自己的使用vim的过程中有些记忆不牢靠的地方,所以记录下来,如何没有帮助你,请不要生气
以下操作是在正常模式下进行的。
如果在两个vim编辑器中,可以使用”yy”&”p”,但是使用这个命令,vim内部寄存器的内容无法推送到系统的粘贴板中,就会导致无法在vi 和其他应用程序之间转移数据,那么,怎么办呢?
在vim的配置文件中: set clipboard
使用 xclip
.
在debian下,
sudo apt install xclip
首先,使用”ggVG”和”y”将所有的vim正在编辑的文本内容发送到xclip程序中,接着打开另一个终端,键入下面的命令:
xclip -o
这个时候再使用“shift” + “ctrl” + “c” copy 到系统的粘贴板上就可以使用了。
这个居然也有快捷键,就是两个大写的ZZ,并且效果等同于:wq
h、j、k、l 分别表示左、下、上、右的移动的方向,其中j、k是在行间移动。 h、l是在行内的字符中移动。
如果想在当前行内快速的移动,则可以使用f、t和F、T命令。
“f“命令移动到光标右边的指定字符上,例如,”fx“,会把移动到光标右边的第一个’x’字符上。”F“命令则反方向查找,也就是移动到光标左边的指定字符上。
“t“命令和”f“命令的区别在于,它移动到光标右边的指定字符之前。例如,”tx“会移动到光标右边第一个’x’字符的前面。”T“命令是”t“命令的反向版本,它移动到光标右边的指定字符之后。
这四个命令只在当前行中移动光标,光标不会跨越回车换行符。
可以在命令前面使用数字,表示倍数。例如,”3fx“表示移动到光标右边的第3个’x’字符上。
“;“命令重复前一次输入的f, t, F, T命令,而”,“命令会反方向重复前一次输入的f, t, F, T命令。这两个命令前也可以使用数字来表示倍数。
在vim中,移动到行尾的快捷键是$,移动到行首的快捷键是0.^是移动到行首第一个 非空的字符处
vim中,移动光标到下一个单词的词首,使用命令”w“,移动光标到上一个单词的词首,使用命令”b“;移动光标到下一个单词的结尾,用命令”e“,移动光标到上一个单词的结尾,使用命令”ge“。
Ctrl-f 即 PageDown 翻页。
Crtl-b 即 PageUp 翻页。
Ctrl + U 向上翻半页
Ctrl + D 向下翻半页
d 命令有这个功能,比如,“dw”,这样留下的是normal模式,使用这个“cw”的模式,可以擦除这个字并且处于插入模式下。
你没有看错,这就是一个 . 命令,让你重复上一次的命令。
“J”命令就是将2行合并一行的命令。
”~”就是这个键。
其中用的最多的就是在插入模式下,输入多余的字的问题,在stackoverflow上有一个问题,就是问到这的,看来我这样的习惯还是不少的。
Ctrl + o 然后你可以随意的使用normal模式下的行为一次。
Ctrl + t 在编辑模式下缩进一个tab键
Ctrl + d 在编辑模式下回退一个tab键
这个在我的配置文件中实现了这样的功能,请使用Ctrl+f寻找一下。
/strings 就是搜索strings的字符串
注意, .*[]^%$~ 这些字符有特殊的含义, 想搜寻他们的话,必须使用”".
从文件的后面向前查找, 在显示匹配高亮的时候,按下”n”,就给你移动到下一条。
”/”是从前往后查找, 如果你接着执行”?”就会让你从后往前找。
首先说明一点,vim的粘贴板其实一直很厉害,关键是自己没有开发出来,vim可以有26个粘贴板的。
当你使用“dw”或者“dd”的命令是,再按一次p就把刚才删除的单词重新复制回来了。
如果你想键入“the”,但是你不小心输入了“teh”, 这是很正常的行为,这里,你可以将光标移动到字母“e“上,接着使用”xp“命令即可。”x”是删除字母e并保存到寄存器中,”p”将文字放到光标之后,”P”是将光标放到单词之后。
这是强悍,你可能都没有听说过的方法。使用标记命令: mark
在你想要删除文本的地方使用命令 ‘ma’
移动光标到你想要删除文本的末尾
使用命令 “d’a”
其中的’a’可以使用其他的小写字母。
使用命令:
: marks
会展示所有的marks,如果使用
: marks args
就会展示当前文件的mark所在的行。
上面marks命令的第三个步骤,可以将d换为y,那样就成了复制一整大的文本。
这个技术用的这不多,这里有两类主要的:
在normal模式下,”!!ls”和”!!date”是最常用的命令。
vim 1.c 2.c 这样就会只打开1.c,如果你想快速切换到2.c,那么需要输入”: next”,在2.c中回到1.c, 需要使用”: previous”.
不在insert模式下,你可以使用”Ctrl+^”来切换这两个文件的编辑。
(注意,我将这个命令在insert模式下改为转为开启Caps Lock键,详情就在本文中)
”: args”就是这个命令。
:split
想要切换编辑的窗口的命令是”ctrl+w”
:split new-file
这块的东西有点罗嗦,
活动的(Action)
隐藏的(Hidden)
未活动的(Inactive)
:buffers
这句命令就是找出所有的buffers.
- Inactive buffer
h buffer is hidden
% Current file
# Alternate buffer
+ File has been modified
当你使用上面的命令,就会列出所有的buffer,怎么选择其中的一个呢?很简单,就是使用
:3buffer
或者
:sbuffer number
其中第一种方法可以在原视图中打开,这样就不会被分割太小了。带”s”的可以看成”split”和”buffer”的合体。
先说一下visual是干什么用的。当你使用这个模式,你可以将某一块的文本选中,并且会高亮,然后你就可以处理其他的事务了。
在normal模式下按下”v”键就可以了。注意这里,按下小写的”v”,是基于字符的visual mode,如果是大写的”V”,那么直接选中整行。如果这时候接着使用”Ctrl + v”则会以正方形的格式呈现。
如同在其他模式下的编辑一样,只不过已经选中了某快区域。
如果你选中了一行的一个字,这个命令就会删除那个选中的字。
如果你选中了一行的一个字,这个命令就会删除整行的字。
发现了一个在写markdown文件有用的文件了,就是使用visual mode选中文本(最好用”ctrl + v”)整体选中,接着按下”>”就可以整体偏移一个Tab键了。
vim融合了很多的指令,这些指令对于你提高开发进度,具有不小的作用。
([CTRL-I, ]CTRL-I)是找出函数定义,这个命令,真的很有用,配合ctags,详情另看我的另一篇文章。
“gd” 是寻找局部的变量定义,”gD”是寻找全局的变量定义。当然,前提是你把光标放在变量处。
在定义的关键词处,按下”[d”两个键即可展示出相关的宏。
无论什么括号,都可以通过”%”来匹配另一半。对于c语言来说,还有评论(/* */), #if,#else,#endif
其他的作用,比如,如果有以下的代码:
void test()
{
{
printf("hello\n"):
}
}
你想着把代码块(里层)的printf语句缩进一个tab键,你可以使用visual mode,然后”>”,你还可以使用”%”键选择括号后,使用”>i{“这个组合,意思就是”inner {} block”
比如,你在写c语言的时候,恰巧不知道这儿的一个系统调用open()怎么使用,你可以将光标放在open上,按下大写的”K”,就可以看到man手册了
这一个在Makefile文件的编写中具有很大的价值,因为Makefile特别注意这样的错误,那么使用
:set list
就可以看出是不是缩进的一个tab键(“^I”)
有两种方式,只不过就是运用命令”!sort”的改进版。这里简单的介绍一种:
利用visual模式选中你想要排序的文本
执行”!sort”
:make
这一部分才是vim对于c的厉害之处,现在,先看一下,其中的奥妙。
在你键入了上面的命令之后,如果没有错误报出,那么恭喜你,你的程序没有语法错误,假如不幸,报错了,使用下面的方法就可以让自己省点时间去调试错误。
先说第一点,就是有错误出来了,那么按一下”Enter”键,就会返回到你的程序的第一个出错点,光标就是定格在那里,不用动。修改完了,使用:
:cprevious
和
:cNext
目测这两个函数不是很好用,那么,
:clist or :cc
就很有用处了。前者是将错误列表重新显现,后者是展现现在的错误。
真没有想到vim还提供这样的命令,
:grep -w printf *.c
在当前目录下grep所有的printf的关键词,其中,”-w”是全词匹配。
好,写了不少了,vim的基本技巧就写道这了,下一次我们开始另一篇神奇之旅。 谢谢!!!
可以直接使用, 在noraml模式下:
:1,ns/old-string/new-strng/g
# $: 最后一个
[2016-08-01]
这个时候,自己更无法平静,看着周围同学一个一个的步入正轨,自己的路到底在何方
即便准备考研,你做好打算了吗?你到底想成为一个什么的人?坚定自己的信念,早日 成为一名kernel hacker.
这道题应该说很简单的,如果不按照给定的函数原型去编写。但是,我的想法是用c语 言,那么,问题来了,关于字符串指针的概念和运用再一次出现在面前。
先看一下函数原型:
char* reverseString(char* s) {
}
那么,返回一个(char *)类型的函数,那么你先必须首先定义一个(char *)的指针用于 接收返回值。OK,char *str;关键参数里也是(char *s),你应该如何处理?我一开始 想申请一个strlen(s)长得字符数组,结果老是报告段错误,所以,不得不参考别人的 代码。
https://leetcode.com/problems/reverse-string/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *reverseString(char *s){
int len = strlen(s) - 1;
if( len >= 0){
char *str = (char*)malloc(strlen(s) + 1);
do {
*str = s[len];
str++;
}while(len--);
*str = '\0';
str = str - strlen(s);
s = str;
}
return s;
}
字符串的长度,不包括结尾的标识符’\0’,例如下面:
#include<stdio.h>
#include<string.h>
int main()
{
char *str = "hello";
printf("The length of str is %d\n",strlen(str));
}
则显示的结果为
The length of str is 5
那么,你在复制字符串时要特别留意这一点。
这里你要注意,指针变量赋给指针变量,并不是把变量所包含的内容赋给左值,而是将 变量的地址传递给对方。比如:
char *str1 = "hello";
char *str2;
str2 = str1;
这里str2的内容并不是hello,或者字母”h”,而是字符串”hello”的首字母的地址。所以 ,如果你想用字符指针来接受字符串,你得首先申请一个足够大的变量。
有了这个变量还不够,如何一个一个字符的赋值?
do{
*str = s[len];
str++;
}while(len--);
这个函数在c语言中很重要,主要在用法上。我的浅显经验是:你想分配什么类型的, 前面就是什么类型。比如:
char *str = (char *)malloc(strlen(s) + 1); // 给'\0'留给空
这里注意一点,str最后一次已经指向了最后一位,要自动的添加个”\0”.
还有一点把我给搞蒙圈了,其实归根结底还是基础不牢靠。
str = str - strlen(s);
s = str;
这里的s是参数,可以作为返回值。那么,为什么要有第一个式子呢?str的指针指向了 最后,如果不把指针回送到字符串首部,那样只会给s一个空的字符。str的加减操作就是移动的指针。
Given a string s consists of upper/lower-case alphabets and empty space characters ‘ ‘, return the length of last word in the string. If the last word does not exist, return 0. Note: A word is defined as a character sequence consists of non-space characters only. Example: Input: “Hello World” Output: 5
这道题目自己思考了很久也没有一个比较好的办法,后来知道,从后往前数的效果好啊。
/*
* File Name: leetcode-58.c
* Author: Bo Yu
* Mail: [email protected]
* Created Time: 2202年08月23日 星期一 08时04分21秒
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* 统计一行英文有多少单词
for(; *p != 0 && *p != 13 && *p != 10; p++){
if(*p == ' ' && tag == 0)
tag = 1;
if(*p != ' ' && tag == 1)
{
n++;
tag = 0;
}
}
*/
int lengthOfLastWord(char *s){
int tag = 1;
int num = 0;
int i;
for(i = strlen(s); i>= 0; i--){
if(s[i] != 32 && s[i] != '\0'){
num++;
tag = 1;
}
else if(s[i] == 32 && tag == 1 && s[i-1] == 32){
return num;
}
}
return num;
}
从这个提交开始,改用c++提交代码*
我发现,leetcode的题目,还得先用一些方法想去做一些预处理,才有可能接下来做题目。 本身这个题目很简单, 就是在string数组里找出最长的前缀子串, 方案是首先把数组排序,然后只 找第一个字符串和最后一个字符串就可以了。
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
int n = strs.size();
if (n == 0)
return "";
sort(strs.begin(), strs.end());
string str1 = strs[0], str2 = strs[n-1];
int s1 = str1.size(), s2 = str2.size();
int p1 = 0, p2 = 0;
while(p1 < s1 && p2 < s2){
if (str1[p1] == str2[p2]){
p1++;
p2++;
} else
break;
}
string ans = str1.substr(0, p1);
return ans;
};
};
这道题目的意思非常简单,就是让你在一个句子中,逆置其中的每一个word,并且每个word之间只有” “作为分隔符。
class Solution {
public:
string reverseWords(string s) {
for(int i = 0; i < s.length(); i++){
if (s[i] != ' '){
int j = i;
while(j < s.length() && s[j] != ' '){
j++;
}
reverse(s.begin()+i, s.begin()+j);
i = j - 1;
}
}
return s;
}
};
说实在的,这个代码非常的干净,也确实非常的优美。
这两篇文章是有共同点的。
这三个函数的作用是类似的。区别只是在参数上的不同。
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
int fstatat(....)
fstat 是传递的文件描述符,lstat是符号链接。这几个函数统一都返回stat结构体,这个结构体的 内容如下:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
尤其注意 st_mode位
#include <unistd.h>
int access(const char *pathname, int mode);
int faccessat(ing fd, const char *pathname, int mode, int flag);
access - check real user’’s permissions for a file
确定文件和目录的访问权限。
参数1是文件或者文件夹的路径。
参数2是要判断的模式,可能值是一个或者多个R_OK、W_OK、X_OK和F_OK(文件是否存在)的组合体。
在
#define R_OK 4 /* Test for read permission */
#define W_OK 2 /* Test for write permission */
#define X_OK 1 /* Test for execute permission */
返回说明,成功为0,失败返回-1,errno被设定为以下的某个值。参考
EINVAL: 模式值无效
EACCES: 文件或路径名中包含的目录不可访问
ELOOP : 解释路径名过程中存在太多的符号连接
ENAMETOOLONG:路径名太长
ENOENT: 路径名中的目录不存在或是无效的符号连接
ENOTDIR: 路径名中当作目录的组件并非目录
EROFS: 文件系统只读
EFAULT: 路径名指向可访问的空间外
EIO: 输入输出错误
ENOMEM: 不能获取足够的内核内存
ETXTBSY:对程序写入出错
相关的代码放在了github上。
这里主要是利用 “或”的关系将那几个模式选中或者删除。
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int fd, off_t length);
这两个函数截取length长得bytes在相应的文件中。
fd = creat(“newfile”, 0744);
指定新创建文件的许可位为
rwxr–r–;
这个参数只是请求,而不是命令, 内核会通过”新建文件掩码”来得到文件的最终模式 ,啥是”新建文件掩码”呢,简单地说,就是,比如说,你要一个文件不能被同组用户和 其他用户修改,那么,你的原意就是将文件的许可位关掉:
—-w–w-
这样即可达到目的。
我们使用
umask(022);
实现了同样的目的。
程序可以通过系统调用chmod来改变文件的模式。
chmod ("/tmp/myfile", 04764);
chmod ("/tmp/myfile", S_ISUID | S_IRWXU | S_IRGRP | S_IRGRP | S_IROTH)
文件所有者就是创建文件的用户,用户通过creat 建立文件时,内核把文件所有者设为 运行程序的用户,如果程序具有set-user-ID位,那么新文件所有者就是程序的文件所 有者。
修改文件所有者和组
chown(“file1”, 200,40);
首先,推荐一本好书:«understanding unix-linux programming»,以下所有的灵感来自于这本书。
这里,重点记忆如下:
充分利用man的联机文档,技巧有
man -k key-word grep “xx”
这样可以有效抓取你想要的联机帮助。运气好的话可能会有code,要多多阅读、仔细阅读。
例如在这段代码中,首先 man who,结果可以知道,这个命令读取的是/var/run/utmp文件,接下来,使用
man -k utmp
可以看到一大堆的东西,学会甄别。
其实光知道概念意义不大,必须还会使用,这些命令的实现的价值也在于此。
int main(){
struct utmp current_record;
int utmpfd;
int reclen = sizeof(current_record);
if( ( utmpfd = open(UTMP_FILE,O_RDONLY)) == -1){
perror(UTMP_FILE); /* UTMP_FILE is in utmp.h*/
exit(1);
}
while(read(utmpfd, ¤t_record,reclen) == reclen)
show_info(¤t_record);
close(utmpfd);
return 0;
}
令人震撼的是read的实现,因为你不必实现知道要写入的结构、类型,只需要事先将结构定义好,然后按照read的使用要求就可以了。
#include <time.h>
time_t time(time_t *t);
功能: 以秒(seconds)为单位得到自从the Epoch的时间。
If t is non-null, the return value is also stored in the memory pointed to by t.
这里是有很多的坑要填的。相关的代码在
struct {
int32_t tv_sec; /* Seconds */
int32_t tv_usec; /* Microseconds */
} ut_tv; /* Time entry was made */
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
需要特别注意的是,年份是从1970年01月01日0:00:00开始计算的。
这就是在处理有关时间的问题时,经常打交道的三个结构体。
接下来是几个比较容易常用的有关时间的函数:
#include <time.h>
char *strptime(const char *s, const char *format,struct tm *tm);
功能: 将一个字符串的时间表达式转化进tm结构体。
这里要注意一下第二个参数,因为有些麻烦,所以最好是需要用的时候man一下。 这个函数在使用的时候,必须首先初始化一下tm。
size_t strftime(char *s, size_t max, const char *format,
const struct tm *tm);
功能: 格式化日期和时间(format data and time),其相关的信息来自于tm,第三个参 数和strptime函数类似,用的时候联机man 一下。
举个例子测试下:
/*
* $ ./a.out '%m'
* Result string is "11"
* $ ./a.out '%5m'
* Result string is "00011"
* $ ./a.out '%_5m'
* Result string is " 11"
*/
Here is the program source:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
char outstr[200];
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
if (tmp == NULL) {
perror("localtime");
exit(EXIT_FAILURE);
}
if (strftime(outstr, sizeof(outstr), argv[1], tmp) == 0) {
fprintf(stderr, "strftime returned 0");
exit(EXIT_FAILURE);
}
printf("Result string is \"%s\"\n", outstr);
exit(EXIT_SUCCESS);
}
上面的注释将这段代码的功能描述的很清楚,也就是用’%Y’等格式化来当前时间关键 字段的输出。
将这两段程序综合起来看,就明白了
```c
#define _XOPEN_SOURCE
#include
int
main(void)
{
struct tm tm;
char buf[255];
memset(&tm, 0, sizeof(struct tm));
strptime("2016-07-06 18:31:01", "%Y-%m-%d %H:%M:%S", &tm);
strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm);
puts(buf);
exit(EXIT_SUCCESS);
}