使用SSH构建内网隧道

之前一直使用学校提供的vpn工具访问放在学校机房内网的服务器,多数时间是没有问题的,但到重大事件时会提高安全防范级别,这是vpn服务器就会关停,在家里工作就傻眼了。于是就想看看是否有什么工具可以穿透内网,保证我有需要的时候可以随时访问。

搜索了一圈后,发现ssh就能实现这个功能。前提是需要有一个可以访问的外网服务器。

假定,内网服务器为N,外网服务器为W。

  1. 在N服务器上可以使用密钥登陆服务器W,这样可以保证登陆时不需要使用密码。
  2. 在服务器N上安装autossh工具,其主要功能是提高ssh链接稳定性,并在ssh连接断开后自动重连。
  3. 在服务器N上执行:
sudo autossh -M 7291 -gCNR 7290:localhost:22 -i ~/.ssh/id_rsa user@W &

这样就可以通过服务器W的7290端口访问服务器N的22端口:

ssh -p 7290 user@W

当然,用同样方法还可以构建其他应用,比如80端口等。

参考:https://blog.csdn.net/upshi/article/details/78630285

ubuntu 18.04中设置dns server

ubuntu 18.04及之后的版本,发生的一个变化,就是网络地址设置的更改。

在之前的版本,修改ip地址、dns地址等都可以在/etc/network/interface中进行修改,dns可以在/etc/resolv.conf进行修改。而在18.04版本后,ubuntu启动了netplan系统,所有这些修改都使用netplan进行调整,具体配置都放在/etc/netplace/*.yaml文件中:

network:
  version: 2
  renderer: networkd
  ethernets:
    eno1:
      addresses: [ 210.77.77.35/24 ]
      gateway4: 210.77.77.254
      nameservers:
        addresses: [114.114.114.114,210.77.68.240]

参考:https://www.techrepublic.com/article/how-to-set-dns-nameservers-in-ubuntu-server-18-04/

python中的for..else语法

学生ppt提到了一个示例代码(现在回过头来看,这个语句对初学者而言,难度有点高了),里面用了一个for..else语法。这个代码让我很诧异。

num=[]
for i in range(2,100):
    for j in range(2,i):
        if i%j==0: break
    else:
        num.append(i)
print(num)

这个示例代码是求100以内的质数。算法本身很简单,但for..else语言在别的编程语言里很少有用到,我算是第一次见到这种逻辑控制,开始我还误以为else是匹配到if中。

在网上搜索后,这个网站讲的很明白:

https://foofish.net/for-else.html

简言之:for..else语句,只要for语句中没有执行break语句,则else中代码必然要执行。

split:分割文本文件

在数据处理时有时需要将一个大的数据集分为几个部分,交给不同机器或不同账号进行处理,之前我都是用sed或vi进行分割,没想到linux有一个专门这样的工具进行处理:split。

split的用法也非常简单,可以按行分割也可以按大小分割。

$ split --help
Usage: split [OPTION]... [FILE [PREFIX]]
Output pieces of FILE to PREFIXaa, PREFIXab, ...;
default size is 1000 lines, and default PREFIX is 'x'.

With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -a, --suffix-length=N   generate suffixes of length N (default 2)
      --additional-suffix=SUFFIX  append an additional SUFFIX to file names
  -b, --bytes=SIZE        put SIZE bytes per output file
  -C, --line-bytes=SIZE   put at most SIZE bytes of records per output file
  -d                      use numeric suffixes starting at 0, not alphabetic
      --numeric-suffixes[=FROM]  same as -d, but allow setting the start value
  -e, --elide-empty-files  do not generate empty output files with '-n'
      --filter=COMMAND    write to shell COMMAND; file name is $FILE
  -l, --lines=NUMBER      put NUMBER lines/records per output file
  -n, --number=CHUNKS     generate CHUNKS output files; see explanation below
  -t, --separator=SEP     use SEP instead of newline as the record separator;
                            '\0' (zero) specifies the NUL character
  -u, --unbuffered        immediately copy input to output with '-n r/...'
      --verbose           print a diagnostic just before each
                            output file is opened
      --help     display this help and exit
      --version  output version information and exit

The SIZE argument is an integer and optional unit (example: 10K is 10*1024).
Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers of 1000).

CHUNKS may be:
  N       split into N files based on size of input
  K/N     output Kth of N to stdout
  l/N     split into N files without splitting lines/records
  l/K/N   output Kth of N to stdout without splitting lines/records
  r/N     like 'l' but use round robin distribution
  r/K/N   likewise but only output Kth of N to stdout

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
Full documentation at: <http://www.gnu.org/software/coreutils/split>
or available locally via: info '(coreutils) split invocation'

简单而言,我将large.csv按照每个2000行进行分割,输入文件名按数字形式命名,则可以:

split -l 2000 -d large.csv

cron脚本中date命令问题

在shell中可以正常执行的命令,转移到cron中让其定时运行发现存在问题,即有错误提示,导致命令不执行。

d=`date -d “1 day ago” ‘+%Y-%m-%d’` && python3 -u regiondata.py –regionfile=region.id –date=$d

此命令问题在于d变量不能获取到,而在shell下执行则没有问题。网上搜索也有同样的问题:

https://unix.stackexchange.com/questions/29578/how-can-i-execute-date-inside-of-a-cron-tab-job

发现解决方案也比较简单,即在%符号前加上\转义,即可执行命令:

d=`date -d “1 day ago” ‘+\%Y-\%m-\%d’` && python3 -u regiondata.py –regionfile=region.id –date=$d

wordpress 5.0.1: gutenberg遭遇updating failed,导致不能保存

wordpress升级到5.0.1后,gutenberg成为默认的编辑器。新的编辑器很漂亮,但一开始使用就遇到了比较糟心的问题:

写好的帖子,不能保存!不能保存!不能保存!

具体的症状就是:在save draft的时候,会提示:updating failed,然后点击publish的时候,会提示成功保存,但到前台则看不到对应的文章,同时在后台文章列表里也找不到对应的文章。文章一点也没有保存!

网上搜索,发现github上有反应类似的issue: issue 2565

但发现其反应的问题,症状虽然相同,但底层原因则不一样,在最后一个帖子里得到提示,有可能是.htaccess的问题。

于是进入服务器后台,删除.htaccess文件,然后在wordpress后台,permalink里重新设置固定链接,其自动生成新的.htaccess文件。

OK,问题解决了!

mac下ppt导出为pdf后文件变大

课后将ppt导出为pdf分享到微信中后发现文件大小超出微信限制了。感到很奇怪,因为ppt本身也只有30MB左右,但pdf有400多MB,导致微信不能分享。这个大小让我很诧异。

开始以为是ppt中插入的图片太大,使用了缩减图片大小功能,并删除了已切除部分图片的内容,重新导出后发现pdf依然很大。

搜索后发现这是mac版powerpoint的一个问题,详见:知乎

简而言之,在mac下的解决方案是:

偏好->常规->打印质量:低。(知乎上选择的是中选项,我发现用低选项,导出的pdf质量仍然可接受。)

PostGIS:ST_xxx函数中ST有什么含义

此前先入为主,一直以为ST的含义是Spatial and Temporal。在课堂上,有学生问我这个含义,我以这个含义进行了解释。但心里感觉没有太大的把握,因此课后回来专门搜索了一下,发现网络上还有人问了这个问题:

https://stackoverflow.com/questions/7234679/what-is-st-in-postgis

从响应来看,最早ST的确是Spatial和Temporal的含义,但在PostGIS的官方文档中是作为Spatial Type进行解释的:

the standard spatial type (ST) prefix.

postgresql: ‘not in’ subquery

在使用sql语句进行查询时突然发现一个语句不能返回合适结果:

select count(*) from weibo.poi where poiid not in (select poiid from weibo.url) and poiid not in (select poiid from weibo.url_bad);

正常应该有结果,但此语句返回空集。
搜索后发现后面的not in语句中存在null值,导致返回空集。因此应该这样修改:

select count(*) from weibo.poi where poiid not in (select poiid from weibo.url) and poiid not in (select poiid from weibo.url_bad where poiid is not null);

巧用pandas进行数据处理

某一原始数据,在数据获取过程中少进行了一个strip处理,导致数据表现为:

,”
2015-01-01 02:56
“,0
,”2018-
01-01 02:56
“,0

其正常应该为一个时间型数据,如:

2015-01-01 02:56
2018-01-01 02:56

而此数据就无法导入数据库进行进一步的处理,因此需要先将其数据进行修正。首先想的是用sed、vi进行处理,但其都是在行上进行处理,而pandas可以在列上进行处理,使其处理不会影响到其他列,因此就使用pandas进行处理:

import pandas as pd
df=pd.read_csv('/path/to/do.csv')
df['ts_created']=df['ts_created'].str.replace('\n\s+','')
df.to_csv('/path/to/out.csv')