您的位置:首页 > 运维架构 > Linux

Linux使用过程中的经验积累

2017-09-21 10:20 267 查看

背景

从2013开始,就一直在xx发布一些工作当中的很易错或总结性的经验积累

我本身就是linux开发工程师,用ubuntu作为办公电脑桌面几年了,也是xx的linux服务器管理员。

linux经验积累

Linux通用

如何完整的cp备份文件夹

如果只是

sudo cp -r /usr/bin /usr/bin_bak


进行备份,那你肯定废了。

第一,软链接的复制必须使用
cp -d
;

第二,更要命的是,owner等关系的复制,必须使用
cp -p


举例,sudo等具有x,w,r之外的第四种权限,即s,表示执行sudo时,是以文件的拥有者身份打开,而不是执行者的身份打开。

如果cp时忘记加-p,那么新复制的sudo就无法被普通用户使用了。

(举例,普通用户执行passwd,passwd会修改/etc/shadow,而普通用户是无法修改/etc/shadow的,所以passwd会有s权限,普通用户执行passwd时,临时获得root权限,从而修改/etc/shadow)

传统的x是无法解决s这个问题的,你可以自己想想就知道了

shellcheck

最近在弄静态检查,发现shell脚本也是可以被静态检查的

apt install shellcheck


即可安装shellcheck.

写完shell脚本,记得用它检查一下,能给你点建议的. 要检查现有项目的所有的脚本,

find your_project_folder -name "*.sh" | xargs -i shellcheck {}


即可.

pip使用公司高速镜像

linux下,创建一个文件

%HOME/.pip/pip.conf


(注意中间的pip前面有个.)

windows下,创建一个文件
/users/administrator/pip/pip.ini
文件加入以下内容即可:

[global] index-url = http://mirrors.xxx.com.cn/pypi/simple/ [install] trusted-host=mirrors.xxx.com.cn


以后执行
pip install xxxx
就可以享受内网的高速安装了!

linux计算性能

计算单核计算能力,一般常用super pi软件.

但linux的super pi很难下载. 可以采用如下语句测试:

time echo "scale=5000;4*a(1)" | bc -l -q


即可比较linux的单核计算性能.

bc是计算器指令,

a(1)是反正切,等于pi的四分之一,4*a(1)等价pi,

scale=5000是精度要求为5000位

sublime text

linux下的sublime text无法输入中文.

解决方法之一:

cd ~/.config/sublime-text-3/Packages;
git clone https://github.com/xgenvn/InputHelper[/code] 
然后,然后就搞定了 ctrl+shift+z就会弹出一个input输入框,上面可以输入中文,回车后,就会进入sublime.

这种方法不是很完美. 有实践过成功的所谓完美解决方案吗?

删除所有东西但不包含XX的简单方案

老方案:

Linux有一个常用的操作, 就是删除所有东西但除了XX.

以前的做法是

find . -not -name 'xx' -not -name 'yy' | xargs rm -rf


来实现, 比较麻烦.

新方案:

其实shell有强化功能,

shopt -s extglob


打开glob的强化功能.

那么

rm !(xx|yy)


就可以删除除了xx和yy之外所有文件, 非常方便.

xmllint

xml文档建议采用xmllint检查一下

ubuntu中

apt install php-xml


即可具有xmllint.

简单的语法检查

xmllint --noout xxxx.xml


即可完成基本检查。

mockcpp

mockcpp其实是个很好用的东西。

编译采用了cmake的方式。

cmake -DCMAKE_INSTALL_PREFIX=/usr/local;
make;
sudo make install


就能搞定编译安装了

通过TCP实现串口交互

问题:

系统测试中,以前为了测试单板的串口,必须在单板附近放一台主机运行测试用例对单板进行串口测试. 我大胆地想象,在不改动程序的前提下,串口数据能否通过网络走掉,这样,现场就不需要加一台主机了

解决方案:

在PC,做一个PTY1(伪终端)并将其链接到PC串口通信用的/dev/ttyS0;

这个PTY1的数据通过网络(我使用最常见的ssh)转到单板里做的另一个PTY2(PTY2链接到单板原来的 /dev/ttySxx)。

那么单板程序在使用/dev/ttySxx进行串口通信时,等价于和远程PC上的串口进行通信.

这样,PC和单板的程序都不需要改动,在没有串口线连接的情况下,实现了远程的串口通信!

由于不受物理串口影响,因此,PC可以创建出N个串口和N多个单板串口同时通信!

详细解决:

我实验了如下语句:

socat -d -d PTY,link=$HOME/dev/ttyS0,raw,echo=0 SYSTEM:"ssh root@you_ip /usr/bin/socat - -d -d 'PTY,link=/dev/ttyS0,nonblock,raw,echo=0'"


socat在网络转发,中继方面非常厉害, 这里采用两个PTY配套通信的原理。

数据写入HOME/dev/ttyS0(放到HOME下是为了解决设备的操作权限问题)。

SYSTEM里的是shell命令,这里是采用ssh登录。

socat 后面的单独的-,表示采用stdin和stdout数据流。这样意味着,两个PTY被神奇得连接起来了!这样就实现了基于网络的串口通信.

其中,-d用于调试,越多个-d,调试信息就越多.

raw代表透明传输

echo=0代表不需要echo回应.

注意:原有的/dev/ttyS0要通过cp -a备份起来,否则,这个socat用完就消失了.

不过不用担心, 万一忘记备份,重启一下设备,原来的tty就恢复了

sscanf

问题:

fortify检查中,发现如下语句,并产生告警

sscanf("%d", (int \*)&char_var);


原因及解决:

c语言的sscanf等系列函数,如果想使用short, char类型,应该要懂得使用h。

h代表half的意思, short 那么就是hd, 半个整形数, char 就是hhd, 四分之一个整形数( unsigned 只需要把d改为u即可).

如果不这么干, 而是”%d”, (int *)&char_var, 这种做法会产生溢出, 下一个跟着它的变量就要倒霉了,莫名其妙被修改,你还查不出来..

端口占用

老方案:

以前查看某个端口是否被哪个进程占用。

都是用netstat加grep.

新方案:

后来发现, 有一个神器 lsof指令。

可以查看linux所有的文件的情况(socket也是文件). 查看什么进程在用什么端口

lsof -i


查看xx端口被谁使用

lsof -i:xx


lsof的可选项非常多, 功能很强大, 输出格式简单明了, 值得深入.

修改时间

最近发现自己的linux和服务器的时间,每次改完,一重启又变掉了.

这里的关键是, linux采用

sudo date -s


命令修改的时间, 不会自动同步到BIOS中,这和windows不一样, 所以一重启又是老样子.

应该加上

sudo hwclock --systohc


与硬件时钟同步,这样才能解决问题

pkill

pkill不加参数时, 很不好用, 杀死进程必须输入全名,

例如”python 全路径程序”启动的程序, 输入全名真让人受不了.

加参数 -f 就非常简单了, pkill -f 后面带一部分文字即可杀死!

例如, python /opt/xx/yy/zz_aa.py的进程名,

pkill -f zz_


即可杀掉进程名包含zz_字符串的进程, 非常方便!

shc

shell脚本是明文的,如果希望内容不公开,可以采用shc工具将shell变成可执行程序.

shc的原理和名字一样,就是将shell翻译为c语言,然后再编译c为可执行程序.

举例, jenkins有人希望可以按某账号提交, 可以写一个脚本,

svn ci -m "xxx" --username=yy --password=zz --non-interactive


然后变成可执行程序, jenkins调用程序即可实现.

这样,就可以做到隐蔽密码的功能。

wget

wget是用来下载的命令,也可以下载ftp协议的东西,

举例, 单板的rom放在ftp服务器上, 我们需要一个命令获取下来, 可以采用

wget -e use_proxy=no --ftp-user=xxx --ftp-password=yyyy ftp://zzzzzzz[/code] 
即可下载下来.

注意, 需要将use_proxy设置为no, 否则公司的代理服务器会无法识别你的内网ftp服务器, 从而下载不了.

本来这个参数要写在~/.wgetrc中,但是,单独在命令行中写,更为方便灵活

比cp更强大的rsync

有了rsync, cp这种过气的指令都可以丢掉了.

rsync不仅可以本地复制,还可以远程复制. 复制的功能强大很多, 例如符号的复制, 复制进度和速度等等.

假设本地一个bin文件,需要复制到单板中, 以前的做法是必须sftp连接上后,进行cp指令. 现在可以

rsync -av ./xx.bin user@ip:remote_foldler


就可以直接复制远程设备的目录上了.

查找设备IP

在linux下更简单查找自己单板IP的方法

单板的sshd服务支持同时监听多个端口, 利用这个特性, 打开

/etc/ssh/sshd_config
,

让Port 22生效并加入自己独特的Port xxxxx.

重启sshd服务后, sshd就会监听xxxxx端口.

这样, linux下

nmap 10.9.81.aa-bb -p xxxxx


就一下子能找到自己的单板了(aa,bb代表ip范围),

只要不重新烧写单板, 普通的升级是不影响它的有效性的.

在~/.bashrc 里加入

alias get_csu_ip='nmap 10.9.81.aa-bb -p xxxxx'


然后source ~/.bashrc让它立刻生效, 输入get_csu_ip就能一下子拿到自己的单板ip了

普通用户使用串口

普通的linux用户无权限打开串口通信的解决方法,不是采用root用户去执行,

最简单的就是将普通用户纳入dailout组

因为linux的串口终端(ttyS)属于dailout组.

sudo gpasswd --add your_user dailout


之后,务必logout 再 login才能生效.

这时普通的用户也可以使用串口通信了.

bash的加载顺序

登录shell时,以下几个脚本依次执行:

/etc/bashrc-->/etc/profile-->~/.bashrc-->~/.bash_profile


/etc下是全局有效的, ~/下的自然是用户自己特有的.

bashrc用来记录alias和function, profile用来记录环境变量, 职责不一样.

其中, 不推荐修改/etc/profile, 因为修改可能导致下次升级时和新配置文件冲突, 因此, 推荐在/etc/profile.d文件夹中新增自己的脚本, 如env.sh, 只要是.sh结尾,都会自动被执行.

因此, 安装软件的环境信息,写入/etc/profile.d/xx.sh中

自己的别名和函数,写在自己的~/.bashrc中, 这样是一个比较好的实践.

bash的ex参数

jenkins的bash运行时,默认带-ex参数.

-x代表每一句执行的代码都会通过+代表层次的打印出来.

-e 就非常关键了, 因为它改变了bash的特性, 默认情况, bash会执行每一行,不管每句是否成功,但加了-e, 中间其中一句出错就会退出, 改变很大.

因此,当需要bash在运行其中语句时,只要其中一句出错就退出,可以加-e参数,-x是更方便调试。

bash判断变量是否定义

bash中,判断变量是否被定义,可以采用

if [ ! -v VAR]


注意这里VAR前面不能有$.

这种方法对4.2版本以上的bash有效

如果bash版本低, 可以采用

if [ -z ${VAR+x} ]


来判断.

注意, if [ -z $VAR ]是不准确的,

因为这种判断如果是没有定义或空字符串的情况都会返回成功.

(定义了一个变量, 如果需要取消, 采用unset VAR 即可). VAR+x这种方式,属于bash的参数拓展, 具体的可以详查资料

svn

svn需要删除一个文件时

svn del xx,


只是删除本地的文件而已, 需要

svn ci -m "..."


提交成功后, 服务器里的数据才会被删除.

但是, 执行svn ci 前, 务必用svn status查看当前的文件夹的状态,否则保证你会提交很多你不想提交的数据上去,然后被团队骂.

举例, 本地执行过make install, 那么很多文件会被修改和新增. 修改的文件, 可以采用

svn revert ./ --depth=infinity


恢复和服务器一样的文件.

新增的属于unversioned的文件, 用revert是无法删除的. 可以采用

svn status | grep ^?|awk '{print $2}'|xargs -i rm -r {}


进行删除.

没有纳入版本的文件, status中是?开头, awk那个是提取文件名, xargs -i 代表将前面传递的参数放入{}中.

svn本地误删的恢复

svn中,如果删除文件夹或文件,采用svn update怎么都无法下载下来时,采用

svn revert --depth infinity folder_name


svn update folder_name
即可恢复.

如果是删除导致路径冲突,采用

svn resolved xxx_name


再更新即可.

svn如何将x执行权限上传到代码库中

linux的svn默认是不会将文件的执行权限上传到服务器的,导致了很多脚本checkout出来后,都必须chmod +x操作。

这种属于治标不治本。

脚本本地给予x的权限再上传是没用的,服务器会忽视x的权限。

正确的操作是

svn propset svn:executable on file.name


, 然后svn commit,这样上传的脚本下次update下来后,才会具有原生的执行权限。

如何创建svn服务器

win下创建svn服务器很容易,其实,linux下创建svn服务器也很容易。有时,需要保存自己的过程文件时,确实没办法,只能自己创建本地svn服务器了。linux安装svn后。

svnadmin create xxx/xxx/xxx/folder_server


一句话就创建完了。

假设需要checkout到本地文件夹为local_code。

svn checkout file:///xxx/xxx/xxx/folder_server /yyy/yyy/local_code


即可。

本地服务器采用file://路径的做法,和远端服务器https://IP的做法有些不同。

svn add your_file


svn commit -m "your commment"


即可将your_file纳入svn管理中。

如果local_code已经有很多文件,那使用svn import 命令吧。

使用ssh实现远程桌面

X11就是X windows system 版本11的意思,用于窗口的位图显示.

linux默认都支持X11, ssh服务一般也默认支持X11转发.

那么当需要打开远程电脑的图形界面时,就不需要VNC或rdp等远程桌面, 只需要在ssh登录中加入-Y, 如

ssh -Y user_name@ip


登录后, 举例,执行firefox,那么就会弹出firefox的图形界面了.

这种方式,不需要全局桌面,只显示你需要的软件GUI, 很是方便, 也不需要额外配置什么.

这其中的原理就是利用了ssh的转发功能, X11的客户端和服务端数据都通过ssh转发实现交互.

自动带密码的sshpass及其交叉编译

ssh登录,除了可以采用密钥实现免密码,对于安全要求不高的场合,可以采用更简单的sshpass. 使用方式:

sshpass -p 'password' ssh user@ip


这样登录时,就不用人工输入密码了.

从github中下载sshpass源码, 默认三部曲会有bug.

解决bug方式:

1.
echo "ac_cv_func_malloc_0_nonnull=yes" > xx.cache


2.
./configure --host=arm-none-linux-gnueabi --cache-file=xx.cache


3.
make
即可实现交叉编译.

vim查看二进制文件

vim如何打开二进制文件呢?

首先

vim -b file_name


然后输入
:%!xxd
即可查看

使用CIFS挂载windows文件夹

对于统一开发环境, 代码可以放在本地, 服务器通过cifs(common internet file system)加载本地文件夹, 通过ssh在服务器上编译.

(这样可以防止代码放在服务器上,服务器挂了,导致无法工作的问题. )

操作方法:设置windows的代码文件夹为共享文件夹(注意权限!), 服务器通过

sudo mount -t cifs -o username=employee_id,password=xxxxxx,dir_mode=0777,file_mo
15ffc
de=0777 //win_ip/share_folder server_folder


即可解决.

注意, mount 是需要root权限的

因此, 服务器的/etc/sudoers中需要加入

%xxgroup ALL=/bin/mount /bin/umount


来给xxgroup的用户赋予mount的sudo执行权限.

服务器采用socks5和polipo上网

作为服务器管理员,需要管理多台电脑,以前的做法是,服务器需要和外网连接时,就用自己的上网认证账号登录.

现在公司做了唯一性认证,这台登录了,那台就掉线了,无法同时使用.

可以采用socks5代理实现.

其他服务器都通过ssh的socks5连接到已经认证的服务器上,那么大家都能同时上网了.

对于不支持socks5的应用程序,可以使用polipo来解决.

polipo可以强制流量全部通过socks5走掉.

下载polipo压缩包,解压,make,复制polipo到/usr/bin即可使用.

创建/etc/polipo/config文件,加入三行

daemonise = true
socksParentProxy = 127.0.0.1:xx_port
socksProxyType = socks5


即可.其中,xx_port就是ssh -D创建出来的那个端口.

最后,

export http_proxy=http://localhost:8123


.这样,普通的程序也可以上网下载了.

其中,8123是polipo默认创建的端口.

基于ssh的socks5上网

ssh服务默认具有socks5代理功能。

如果一台电脑A具有更高的上网权限,而且它具有ssh服务.那么,其他电脑可以通过

ssh -fND localhost:xx_port user_A@ip_A


即可实现通过那台电脑来上网.

举例,firefox的高级-网络-设置中,选择手动代理,将除socks5以外的全部清空,socks5填入127.0.0.1 xx_port.

那么,firefox上网时,就会走那台电脑来上网,这样就可以访问更高权限的网页了

ssh压缩

SSH传输,可以开启压缩功能,就是将内容进行gzip压缩。

对html这类文本传输的协议效果尤其明显。

做了一个测试,

正常web访问,耗费170K流量,

用SSH隧道,也是170K,

但是SSH隧道加上压缩功能,就只需要20K了,仅为原来的11%!

省流量的效果非常明显!

对于SNMP,由于都是一条条命令交互,内容越少,SSH隧道附加的内容就会相对显得越多,压缩效果也没这么明显。

实测,walk获取324条数据,

普通轮询需要55K,

SSH隧道用了95K,

SSH隧道加上压缩用了58K,反而多了5%的流量消耗。

因此,SSH隧道压缩特别适合在html、xml等文本传输的协议中使用。

ssh自动维持链路autossh

当ssh处于移动网络时,容易出现断开的问题,这时可以采用autossh。

它会间接调用ssh,但是加入了链路检测。

编译:将Makefile中的gcc改为交叉编译gcc,ssh的路径改为单板的ssh实际路径即可。

用法:原来ssh的语句,将开头的ssh改为

autossh -M port


即可,-M后的端口是autossh用来检测链路用,要确保port和port+1可用即可。

检测的原理:autossh会额外加入如下命令(假设-M后是6000):

ssh -L 6000:127.0.0.1:6000 -R 6000:127.0.0.1:6001


很明显,对本地6000端口发检测包,最终又会回到本地的6000+1端口,这样就能知道链路是否断开,如果断开,它会自动重连

基于密钥的ssh免密码免人工确认登陆

第一步,免密码,网上讲的比较多:

开发阶段:用

ssh-keygen -t rsa


生成密匙对,建议改掉默认名,举例这里

私钥为id_rsa_esmu,

公钥为id_rsa_esmu.pub。

将私钥放入单板文件系统的/root/.ssh中,公钥给客户。

客户:建立一个我们单板将要登陆的用户A,将公钥放入(假设为linux系统)A的home目录下的.ssh文件夹下,将公钥导入认证钥匙中,

cat ~/.ssh/id_rsa_esmu.pub >> ~/.ssh/authorized_keys


第二步,实现免人工确认的登陆

单板:加入ssh和ssh-keyscan指令

ssh-keyscan -H ${client_ip} >> ~/.ssh/known_hosts,


然后

ssh -i ~/.ssh/id_rsa_esmu A@{clinet_ip}


就可以自动登陆了。

免人工干预最关键的就是使用了ssh-keyscan,它可以免人工确认的生成known_hosts文件。

ssh反向隧道实现内网设备的访问

假设单板处于内网,客户无法访问单板的web,怎么办呢。

这里可以采用ssh**反向隧道**实现。

例如,在单板输入

ssh -f -N -R 8888:localhost:80 mania@10.9.81.xxx


其中,-f -N配合使用,将这条指令变成后台运行,-R代表反向隧道,8888是在客户电脑的tcp端口,80是单板的tcp端口,mania是客户电脑提供的普通操作系统用户,@后的是客户的电脑IP。

localhost:8888(127.0.0.1:8888)


就可以访问单板的web了。非常简单。

对于多个单板,客户电脑的端口要设置成不一样,每一个端口对应不同的单板。另外,这个方法只限于TCP,所以web适用,snmp等采用udp的将不适用。

基于SSH隧道的UDP

ssh隧道只支持tcp的端口转发,对于snmp这种使用udp的协议,需要增加tcp和udp之间的转发。

这里采用socat实现。

假设处于内网的单板采用6666端口ssh反向隧道公网IP电脑的6666端口。

在公网IP电脑上执行

socat udp4-listen:1610,reuseaddr,fork tcp:localhost:6666


在单板上执行

socat -v tcp4-listen:6666,reuseaddr,fork udp4-sendto:localhost:161


那么snmpget 公网电脑的1610 udp端口,等价于snmpget 单板的161 udp端口,这样,网管就能通过snmp主动轮询单板了。

sudo的环境变量

使用sudo时,环境变量即不是来自当前用户,也不是来自root用户.

为了安全,它只留了几个最基本的环境变量,如果需要继承当前用户的环境变量,需要加 -E

例如,ubuntu使用

sudo add-apt-repository ppa:


添加源时,往往会失败,根本原因就是没有继承当前用户的proxy的环境变量,导致连接不了网络,加入-E,就能正常添加了.

其他程序类似问题也是如此解决.

至于sudo echo $XX, 能打印输出XX的内容,本质是shell在运行这个时,直接替换了XX对应的内容,如果sudo要执行的是一个程序或脚本,就会发现环境变量进不去的问题.这时就要使用-E了

软件安装了却无法使用pkg-config查找库和头文件路径

软件安装包一般会有自己的库和头文件路径,一般不需要记忆,最好通过

pkg-config xxx --libs --cflags


来获取库路径和头文件路径。

但是,有些系统的某些软件明明安装了,pkg-config却弄不出来,如最近的SUSE系统的openssl。

pkg-config查找的本质是查找xxx.pc文件,find / -name openssl.pc,找到文件,然后查找某个可以使用pkg-config的aaa,并找到aaa.pc的路径,将openssl.pc复制到aaa.pc所在路径,就可以解决pkg-config定位不到openssl的问题了

ftp服务新增用户的安全操作

linux建ftp服务器,有一些坑,这里以ubuntu中采用vsftpd(vs为very secure)为例。

apt-get安装vsftpd后,新增一个用户

sudo useradd -m ftp-user -g ftp -s /usr/sbin/nologin


-m意思是给ftp-user建立同名的home路径,即/home/ftp-user,如果没有这个路径,ftp连接时,会出现500:OOPS不能改变路径的错误。

-s指定的是采用什么shell,这里是为了限制上述新增的用户具有登陆的权限,这时,要在/etc/shells新增这个/usr/sbin/nologin,否则ftp服务在pam验证时,会因为nologin不在shells文件中,而拒绝用户登陆(另一个方法就是,不使用pam验证,将/etc/vsftpd.conf中pam验证对应的vsftpd改掉,随便改一个在/etc/pam.d中没有的关键字即可,如ftp)

为了防止用户具有文件夹到处乱跳的权限,必须chroot。

在/etc/vsftpd.conf中使能chroot,并新增一句

local_root=/aaa/bbb


其中,bbb文件夹的拥有者必须是前面新增的用户,因为vsftpd根据安全不允许非拥有者具有w权限,否则无法写入,常见语句为:

sudo chown ftp-user:ftp /aaa/bbb; sudo chmod 755 /aaa/bbb
在/etc/vsftpd.conf中使能local_user和加入写权限等操作后,

sudo service vsftpd restart
即可。

通过本机的ftp localhost可以验证效果。

GUI可以使用filezilla,比较友善

nmap扫描自己的设备

周末停电,单板被重新分配IP,单板没有液晶,也没有作弊用的串口线,如何最简单的知道单板IP?

采用linux的网络扫描神器nmap指令

sudo nmap 10.9.81.xx-yy -p 22 --open


意思是扫描从xx到yy这个ip范围设备,-p 22为tcp端口22(sshd的监听端口),–open表示只显示那些打开状态的端口。

这样,罗列的设备中,MAC地址是你设备的那个IP就是你需要的信息了。注意,这里需要root权限执行,返回的结果才会带有mac信息。

为什么不使用typedef

为什么linux要反对使用我们用滥了的typedef。

linux内核规范认为,typedef出来的类型,会降低可读性,没人知道foo_t这个类型到底是结构体还是指针还是联合体。

对我而言,我看中的是另外一点,就是struct foo foo这种定义是合法的。struct foo foo第一个foo是在tag空间里,后面的foo是在变量空间里,所以重名合法,这可以解决结构体命名和它对应的变量怎么命名区分的烦人问题。然而,typedef出来是type,是不允许和变量重名的,自己解决命名的问题吧。

为什么要使用cron来执行周期任务

linux中的周期或定期执行的任务,你还在自己写程序计时实现吗?

可以使用linux的cron指令。

cron是一个专门负责周期,定期执行任务的指令。使用它有如下好处:

1.可以实现你能想到的各种周期执行方式;

2.简化代码,代码不用再重复制造轮子;

3.cron的设计考虑的很周全,如,时钟被改变的情况等情况都考虑进去了;

4.节省cpu,我们的代码都是硬累加变量,不断地判断,而cron采用sleep的唤醒方式,尤其是有多个周期任务时,自己实现的代码每个都要自己不断累加变量,而cron是统一判断时间,这样可以节省很多cpu时间;

5.我们的程序自己执行任务几乎都是阻塞的,cron通过多次fork的方式,没有阻塞问题。

使用cron来周期压缩日志

单板本身就有cron的指令。首次使用时,保证有文件夹

mkdir -p /var/spool/cron/crontabs


crontab -e 可以进入编辑模式.

假设需要每天的0点时执行压缩日志的任务,输入

0 0 * * * tar czf log.zip /var/log/xx.log


然后运行crond即可实现。

0 0 * * *代表0分0时任意日任意月任意星期。

crontab是负责配置cron用的另一个工具。

如果需要每3小时周期执行一个任务,可以* /3 * * xxxxxxx即可。

由于单板默认有且只有root用户,因此配置信息都会写入

/var/spool/cron/crontabs/root


的文件中。

另外,如果新增,修改配置信息,crond是不用重启的。

双网卡的静态路由配置

当服务器配置了双网卡时,一般情况下,你会发现其他电脑连接不了第二张网卡(eth1),除非其他电脑恰好和服务器的eth1在同一网段。

为什么呢?原因是:eth0会默认将所有的地址走eth0获取的网关0,为了不产生冲突,轮到eth1时,无法采用这个策略,因此,eth1一般是没有默认网关的,必须自己配置。采用

route add net xx netmask yy gw zz


的方法虽然可以解决问题,但是,重启或拔插网线会导致这个新增的路由信息丢失。

网上有很多静态配置路由的方法,经过实践都不靠谱,后来发现,在ubuntu的人机界面的网络连接里的路由新增一条信息,非常简单就可以达到新增静态路由的效果了。

另外,同一网段下,信息的交互是不用走网关,直接由你的网卡转发实现。

exit使用

关于代码里,有exit(0),exit(1)的使用,很多人只关注了它退出程序的作用,却忽视了中间数字的作用。中间的数字,是程序退出时的返回值。通过

echo $?
指令,可以获取上一次程序或命令执行的返回值。

默认情况下,程序成功运行时,会返回0,失败会返回大于0的值。但人为的加入exit(x),当程序通过你的exit(x)退出时,就会返回x,根据x就可以知道在哪里退出了。

另外,
echo $?
不能连续使用,因为第一次执行
echo $?
时,这条指令是成功运行的,所以值就会被修改为0,下次
echo $?
就只能拿到上次
echo $?
的返回值0 了

使用expect实现交互自动化

linux的expect指令可以实现人工交互的自动化,举例,有些登录需要人工输入密码,如果想全程自动化,那么可以使用expect.

expect可以让平时的很多人工操作自动化. 该指令需要额外安装.

一个简单用例如下:

#!/usr/bin/expect


,让expect处理这个脚本,而不是bash;

set ip [lindex $argv 0]
,

让第一个参数存入变量ip中;

spawn ssh root@$ip
,

登录单板,其中spawn会新建一个进程;

expect "password"
,

如果程序输出有password的关键字;

send "your_password\r"
,

那么就发送你的密码,注意,这里一定要有\r回车;

interact 表示进入人机交互界面. 这样就实现了另一种免输入密登录单板的途径了

为什么需要使用nohup启动后台程序

关于进程在后台运行的问题.一般人的操作都是在程序后面加 &.

这样有个局限,就是终端关闭了.这个后台运行的程序也会被关闭.

通过
pstree
指令可以看到上述操作,终端是作为父进程,关闭终端,会收到SIGHUP的信号,SIGHUP会继续传递给子进程,这就是为什么终端关闭,加了&也会死掉的原因.

可以执行

nohup your_program &


也就是开头多加nohup就行了,意思是不让SIGHUP传递给子进程.

原来被执行的程序是沿用了终端的stdout,stderr的, 终端关闭,执行程序也就无法输出了,因此,nohup还会做一件事,就是断了和终端的联系,所以nohup会让程序的输入,输出重定向,自然终端上就不会显示输出了.

stack的上限

我们单板的stack上限是8M,和PC版的linux一样。

如果stack里的数组(如函数的局部结构体数组)会存储比较多的东西时,就要检查一下是否会超过8M了。

以前在解析工具中碰过超出了8M的stack上限的问题。

在单板中,没有
ulimit
指令供使用。需要用库函数获取,

#include <sys/resource.h>
struct rlimit rl;
getrlimit(RLIMIT_STACK, &rl);


后 rl.rlim_cur 就是系统的stack上限了,检查一下stack里的巨型数组是否超过它,是非常有必要的。

gdb如何不被信号中断

如果一个程序需要接收SIGHUP信号,那么gdb调试它时,收到正常的SIGHUP信号也会让gdb停止下来,在gdb中输入

handle SIGHUP nostop


那么程序再收到SIGHUP时,也不会出现烦人的停止了。

如何自动新增一个用户

自动新增一个用户,正常adduser指令会要求输入密码,让脚本阻塞。

可以adduser 中加入-D,即不需要密码。然后通过

echo -e "$password\n$password\n" | passwd $user


来给刚才的用户新加密码。这样脚本就不需要阻塞了。

动态库依赖查看

查看动态库的依赖,一般来说用
ldd


对于嵌入式的busybox,默认没有ldd,这时可以在PC上使用

arm-none-linux-gnueabi-readelf -d


来查看动态库的依赖关系,也可以查看交叉编译后的执行程序的依赖关系。

strict-aliasing

在gcc(或交叉编译)的编译选项中有 -fno-strict-aliasing,意味着要去除O2优化带来的影响。

gcc在O2优化时,会开启-fstrict-aliasing,通过

gcc -Q -O2 --help=optimizers


可以看到-fstrict-aliasing处于enabled状态(O0优化是disabled)。

-fstrict-aliasing的意思是,假设内存的同一个位置不会被不同类型的指针同时指向,所进行的优化。

程序员如果干了这样的事,在O2优化时,就有可能有不同的输出结果。

在优化性能可以接受的情况下,为了减少这样的麻烦,加入-fno-strict-aliasing,可以保证不同的Ox有相同的输出。

如果不能接受,可以加入-Wstrict-aliasing,在O2优化发现内存有不同类型指针同时指向时,会产生告警提示

zip去除文件路径

linux的zip命令,默认会将路径信息加入压缩包中,解压后会保留原文件路径的文件夹,加入-j即可去掉文件夹信息(junk),如,

zip -j xxxx.zip xxxx.xml


.另外,zip不像bzip2压缩后会删除源文件,需要额外rm一下。

新建文件的默认权限

linux在新建一个文件时,都有一个默认的权限,这个默认权限可以通过
umask
指令进行修改。

umask可以查看现在的权限,如0002.意味着other的w权限会失去。

注意这里是umask,和mask的逻辑正好相反。umask 0000,意味着不屏蔽权限。

inotify机制

linux的inotify机制。如果需要监视文件夹或文件,例如文件夹新增、删除、修改文件,文件内容改变,属性改变,时间改变,是否被打开、关闭等的需求,都可以使用inotify机制。

这是一种源于linux内核和文件系统的基于事件的机制。相比古董式的轮询方法,它具有节省cpu资源和非延迟的特性。推荐使用。

如何在bash脚本中运行python语句

linux的bash脚本如果需要嵌入python语言实现更复杂的实现,只需要python -c ‘xxxxx’即可,xxxx可以是多行的python代码。

举例

echo "good"
python -c 'print("bad");print("normal")'


这对于拓展bash脚本非常实用。

xshell中误按ctrl+s锁定屏幕的解决方法

由于ctrl+s是绝大多数软件的保存快捷键,有时xshell处于选中状态时,不小心按到ctrl+s,那个窗口就无法操作了。

最笨的方法是关掉重新连接。

其实,在linux中,ctrl+s是锁定屏幕的意思,屏幕没有动,但是键盘的操作仍然是继续的。

解决方法:按下ctrl+q就可以解锁了。

如何用init管控自己的进程

在/etc/inittab中,可以加入init进程管控的进程。

这里有个问题,就是会发现ssh连接后,我们的进程怎么都不输出打印信息了。ssh连接后,执行tty,可以发现输出/dev/pts/x (x为数字),第一个打开的ssh的x为0,后面的ssh依次增加。这说明远程终端名为pts/x,那么inittab中就可以,举例:在inittab中加入一行
pts/0::respawn:/root/power/bin/snmpd


当打开第一个ssh时,就可以输出snmpd进程的打印信息了。

respawn参数告诉init进程,无论snmpd进程什么时候挂了,都必须重启起来。

中间两个冒号之间应该为执行权限数字,留空意味着,不管什么权限,都要执行这句话。

最右边的语句再长,也不需要引号括起来,直接写即可,加引号反而是错的。

如何搜索文件夹下的所有文件是否包含某字符串

可以

grep target_str folder_path -r




grep gcc ./ -r


即可查找当前文件夹下包括子文件夹的所有文件中包括“gcc”字符串的输出。非常实用

关于使用cd切换目录无效的易错点

一个常见的易错点,linux中很多人会用

system("cd /xxx/xxx")


试图改变当前进程的路径,其实这是无效的,因为system会新开一个进程执行shell指令,完成后返回,因此,cd改变路径并不会影响当前进程,这就是无效的原因。

进程如果需要改变路径,应该使用
chdir
函数。

sftp开放只读路径的安全操作

如果需要在linux中开放一个只读路径给客户读里面的文件并且考虑安全因素,可以采用sftp,设置如下:

1.新增组:

addgroup sftpusers


2.新增用户new_user并加入刚才那个组

adduser -s /bin/false -G sftpusers new_user


(注意:/bin/false的作用是阻止new_user通过ssh访问并乱搞,否认用户执行/bin/sh或/bin/bash来操作你的设备,这对安全很重要)

3.限制用户只能访问一个路径,编辑
/etc/ssh/sshd_config
,到达文件最后,找到Subsystem和Match那两句注释掉,在最后加入如下:

Subsystem sftp internal-sftp
Match Group sftpusers
ChrootDirectory %h


(ChrootDirectory 后面跟的是登入用户的根目录,%h代表用户的home路径,这里等价为/home/new_user路径,由于这个就是根目录了,所以登入的用户无法跳到其他地方去,这样用户只能访问这个路径下的东西了,这对安全很重要)

chown root /home/new_user
chgrp sftpusers /home/new_user
chmod go-w /home/ /home/new_user


这样就搞定了

如何查询硬件信息

linux下如果需要查询硬件信息,可以使用
dmidecode
指令,

举例,

sudo dmidecode | grep CPU


可以知道当前linux的cpu硬件信息。

dmi指的是desktop management interface,

是管理工具和系统层之间的接口,它遵循SMBIOS(system mangement BIOS)行业规范进行硬件资源的获取。

由于DMI和SMBIOS都是行业规范,因此,是一个跨平台和跨系统的通用使用,不仅仅局限在linux。

gdb如何查看内存值

gdb中如果需要查看内存的值,可以使用x指令,

x/n addr
表示打印addr开始的n个单位的内存值,

嵌入式arm单板CSU的单位为byte,pc机的linux系统为int。

如果不想采用默认单位,

x/nb
输出n个byte,

x/nw
输出n个int。

如何采用sed匹配多关键词

当使用sed进行多关键词匹配时,如关键词为X,Y,Z,则可以

sed -n "/X/{/Y/{/Z/p}}"


即如果需要新增关键词时,规律为在p在左边加上{/key_word/,右边加上}

建立tftp服务

ubuntu建立tftp服务器的方法如下:

sudo aptitude install tftpd
,一般会默认安装上xinetd,如果没有,额外安装即可。

创建
/etc/xinetd.d/tftp
这个文件,在里面写入

service tftp {
protocol = udp
port = 69
socket_type = dgram
wait = yes
user = nobody
server = /usr/sbin/in.tftpd
server_args = -s /home/mania/xxx
disable = no }


其中,/home/mania/xxx改为你需要分享的路径即可。

使用
sudo /etc/init.d/xinetd restart
重启xinetd即可

(注意:service xinetd restart的操作无效)检查是否成功。

如果没有tftp则sudo aptitude install tftp。然后

tftp localhost


get xxx


xxx为分享文件夹下已有文件名,如果成功,会有提示 。

另外,你可能会问:

tftp为什么和xinetd扯上关系了呢。

xinetd其实是个好东西,被称为internet superserver,可以理解为TCP Wrapper。

原来的各个网络进程都要作为daemon监听端口,浪费资源。

xinetd作为老大级驻守进程后,小弟就不需要再监听端口了,xinetd监听所有给它配置的端口。

例如,tftp的69端口发来一个请求,xinetd收到后,立马通知对应tftpd干活。这样,众多的进程平时都不用启动,只需要启动xinetd统一管理即可。非常好的东西!它还有其他很多优点,有兴趣可以去了解它。

sed的一个实例讲解

sed功能很强,但也不好理解。

前段时间做了一个configure后自动修改Makefile的命令

sed -e '/^agent:/,+2{s/^/#/g}' -e '/^all:/i\agent:\n\t@(cd snmplib; $(MAKE))\n\t@(cd agent; $(MAKE) )' -e '/^install:/,/(OTHERINSTALL)$/s/^/#/g' -e '/^uninstall:/i\install:\n\t@cp agent/snmpd ../../bin' -i Makefile


真像天书。注释如下:

-e 是分隔不同命令的符合,

/^agent:/表示找到agent:开头的语句,^表示开头,

,+2表示后面两行的范围,即找到agent:开头的语句,再加上2行,一共3行,执行后面的{s/^/#/g}操作。

后面表示将所有的开头替换为#,即开头添加#的意思,s代表替换,g代表全文全局有效。

第二句:找到all:开头的语句,i\代表在目标行前插入,插入内容就是后面的内容。

第三句是找到install:开头的语句,有效范围到可以找到(OTHERINSTALL)$关键词的语句为止,然后执行后面的开头添加#操作。

第四句,自己理解即可。整体而言,还是够复杂的。。。

使用宏作为代码生成器

宏作为代码生成器很有用。

gcc4版本之前,采用##进行连接的方法,在gcc4版本后有所改动,当出现句号,逗号,空格,等号等,将可以取代##的作用。

举例

#define FUCK(x) fuck_f##x##=True


以往版本是可以的,gcc4就会报错,因为=可以取代##,应改为

#define FUCK(x) fuck_f##x=True


这样FUCK(7)就等价为fuck_f7=True

另外,宏定义也支持多变量,举例,

#define FUCK(x,oth...) fuck_f##x={oth}


那么,oth就代表了输入的多变量,这个只能放在最后,FUCK(7,1,2,”good”)等价为fuck_f7={1,2,”good”} 。

最后,如果int i=7;那么FUCK(i,i)将等于fuck_fi={7}而不是fuck_f7={7},这点要注意理解

如何统计文件夹有多少个文件

linux下统计某文件夹有多少个文件,可以

ls -lR | grep '^-' | wc -l


ls -R代表包括子文件夹;

‘^-‘代表一般的文件,如果是统计文件夹,则为’^d’;

wc -l统计输出行数

vim缩进的方法

vim缩进的方法:

全文自动缩进gg=G,gg为回到第一行,=为自动缩进,G表示最后一行。

局部缩进可以,n==,n表示光标下的连续n行自动完成缩进,省略n时,为当前行执行。

>>为indent,<<为unindent,==为auto indent。局部自动缩进,也可mG=nG。

vim处理括号里内容

vim处理括号里内容可以采用,[d,y,v]i[符号],例如,一个光标在一个括号内,di(或di)都可以将括号里的内容剪切掉,如果需要加上括号,将i改为a即可,同理可推导其他组合。如果需要将某些行移动到X行的后面,可以,: 3,23 m 45 ,m即move的意思。

linux下如何用串口进行调试

在Ubuntu下如果需要串口连接CSU进行调试,可以在软件中心直接安装serial port terminal的软件,注意,这个玩意的运行名称居然叫gtkterm,而且sudo gtkterm才能打开串口。因为串口属于dialout组,sudo肯定可以打开,否则需要将自己加入dailout中,设置波特率为115200后就可以像windows下的xshell一样调试CSU了。

为什么sudo cd无效

当某个文件夹只有root用户可以登入时,采用sudo cd会显示无此命令。

原因是,cd属于shell的内置命令,不是linux的系统命令,因此,sudo cd是无效的。

在shell中输入help,可以显示所有的内置命令,包括echo、alias、source、pwd、kill等常用命令。

要cd到root权限的文件夹,只能su,作为root用户才能登入。

(另外,sudo -i的意思是,会加载root的profile和bashrc后再执行,不加-i,就是使用原有用户的profile和bashrc参数,这点要注意,很易错)

linux中文版的home文件夹切换为英文

linux安装时如果按中文安装,home路径下的文件夹名称为中文,输入非常不方便,可以采用

export LANG=en_US && xdg-user-dirs-gtk-update


变成英文文件夹名称。

也可以一劳永逸的解决:将

/etc/default/locale
里的内容改为

LANG="en_US.UTF-8"
LANGUAGE="en_US:en"


注销,重新登入即可。

docker环境量

对于
docker .... bash xxx.sh
这种运行xxx.sh脚本的方式,环境量是个问题。

这种方式的环境量不等于你采用
docker -it bash
进入的人机交互界面。

很多在.bashrcprofile甚至在/etc/environment里定义的环境量,都无法使用。

但是,采用Dockerfile生成的镜像却可以解决环境量的问题。

在Dockerfile里有两句即可。

FROM your_docker_image:image_tag ENV PATH $PATH:/opt/arm-2011.03


这样,在bash中执行

docker build -t your_docker_image:image_tag


那么,你原来的镜像的PATH环境量就会新增一些值了。

删除同名镜像的容器

当需要删除所有同名image的容器时,可以采用

docker rm $(docker ps -aqf ancestor=image_name)


-f代表filter,ancestor=image_name代表是过滤规则。

-q代表仅输出容器id

-a代表所有的容器。

这样,
$(docker ps -aqf ancestor=image_name)
就会依次输出同名image的所有容器id,供rm删除。

为什么export和alias不生效

由于经常换板或烧片,每次都要配置自己的单板环境很麻烦,因此,将常用的设置变成一个脚本,烧片后,复制到单板然后执行就非常方便了。

结果export和alias总是不生效。后来发现,是因为我采用sh file_name 或./file_name的方式运行脚本。

这种方式本质是新建一个进程,再执行,当前打开的shell当然无法使用alias或export的成果了。

正确方法为:

source file_name
. file_name


.是source的简写,一样的效果。source的作用是在当前的shell执行脚本,所以export和alias会生效。

xshell部分场合无法使用退格键的解决方法

xshell在部分场合下,按退格键,会出现奇怪的字符,无法实现删除的效果。

打开窗口属性,找到“键盘”,将BACKSPACE键序列改为backspace选项即可。

安卓上如何运行linux

安卓上是可以跑ubuntu的

由于安卓使用了linux的内核,采用chroot的方式,建立ubuntu的根文件系统,加入一些group的权限,安卓通过ssh或vnc访问ubuntu.

安卓上加载ubuntu.iso镜像文件,并使用的原理,关键在于使用了回环设备。通过

losetup /dev/block/loopXXX ubuntu.iso


把镜像文件建立成一个回环设备,

再将这个回环设备mount到安卓的一个目录下。

那么操作这个目录,就是等于操作ubuntu了。

android必须使用转发功能,ubuntu才能收到数据。

linux运行中,如果需要改变内核的参数,例如,我需要增加ipv4的转发功能。可以这么干:

sysctl -w net.ipv4.ip_forward=1


或利用/proc里面是内核虚拟文件的原理是用

echo 1 > /proc/sys/net/ipv4/ip_forward
来改变。

如果想重启有效,那就修改/etc/sysctl.conf文件吧。

lftp

交叉编译的文件怎么放到单板上呢?

lftp -u user,password sftp://csu_ip <<EOF cd remote_directory lcd local_directory put file_name1 get file_name2 bye EOF


注解: EOF是表示结束的标志,不一定用这个

put就是上传,get就是下载

stderr和stdout都追加到log日志

如果基于bash4,可以采用新语法:

exec command &>> xx.log


无需使用老款的(2>&1)

新语法的&就是将stderr和stdout都重定向的意思。

(>>是追加的意思)

Ubuntu

ubuntu安装缺少的库

当缺少一个库时,如何知道需要安装什么,才能拥有这个库呢?

Centos下有yum whatprovides

ubuntu下却没有相同的东西.

但可以有如下两个方法解决:

1. http://packages.ubuntu.com/ 里查找

2. 使用apt-file search 查找.

都能解决库的所属问题.

ubuntu16.04安装phabricator

ubuntu通过

apt install arcanist


即可完成pha的客户端必要工具安装.

这里有个坑,就是ubuntu16.04仅用这个还不够.

否则在执行arc diff时,会出现包含”SimpleXMLElement”关键字的一些错误.

坑了很久,才发现增加

apt install php-xml


即可补全这个必要的库.

ubuntu16.04安装RobotFramework-Ride

RF的ride在__init__.py文件限制了wxpython只能使用2.8。

ubuntu16.04里的wx都是3.0以上的版本,装回2.8很是麻烦.

其实,只要手动修改__init__.py,在 支持版本那加入”3.0”即可。

重新运行ride.py,正常执行.

64位系统运行32位程序

问题:

在ubuntu 64位的系统中,如果有32位的应用程序需要在64位,那怎么执行呢?

解决:

可以根据缺失的库名加:i386来安装。

例如:

sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386


安装完后,依赖这些库的32位程序就可以跑起来了.

unity

忍不住升级了ubuntu. 升级到15.10后,桌面没有panel.

ctrl+alt+t可以打开终端, 输入unity, 打印信息发现是compiz出问题了.

dconf reset -f /org/compiz/


即可恢复compiz的设置,

注意这里最后的斜杠是一定要的

(不同的软件,对最后的斜杠处理逻辑是不一样的).

这时, 再次通过

setsid unity


打开桌面即可出现久违的panel.

setsid的意思是新起的进程和父进程无关,这样,shell终端关闭也不会影响unity桌面.

setsid的用法和nohup以及& disown的效果类似.

xfce4远程桌面的tab失效

ubuntu的unity无法远程,所以一般会安装xfce4桌面。

安装:

sudo apt-get install xrdp
sudo apt-get install xfce4
echo xfce4-session >~/.xsession
sudo service xrdp restart


xfce4远程桌面的tab失效解决方法:

xfwm4-settings,选择key-board,找到Tab一行,清除即可。

ubuntu远程桌面到windows

ubuntu默认安装有remmina,该软件可以远程桌面windows,非常好用

CentOS

CentOS安装Jenkins

问题:

在Centos上安装jenkins,如果jenkins上执行sudo指令,会出现“Sorry, you must have a tty to run sudo”的错误.

原因:

在于CentOS的
/etc/sudoers
里有一句“Defaults requiretty”

这句话要求sudo的运行必须有一个tty,但实际上又没有多大的安全作用(ubuntu已经没有这句了)。

解决:

将这句注释掉, 以后执行sudo就不会有这个错误了。

CentOS安装缺少的库

问题:

执行程序少共享库,举例,libstdc++.so.6, 直接yum安装提示找不到这个库.

解决:

最有效的方法是, 采用

yum whatprovides libstdc++.so.6


这样可以获得想要的答案。

运行结果回复是选择libstdc++-4.8.5-4.el7.i686。

那么安装了libstdc++-4.8.5-4.el7.i686, 就可以安装到我们需要的libstdc++.so.6了

开启vsftpd服务

CentOS7开启vsftpd多了一些坑.

这里按vsftpd自己监听21端口为例.

1.为了连接成功:需要将vsftpd.conf的listen_ipv6注释掉, 将防火墙关掉

sudo systemctl stop firewalld.service


为了增加本地用户的写权限,需要在vsftpd.conf增加

allow_writeable_chroot=YES


,同时,在shell中执行

sudo setsebool -P allow_ftpd_full_access=1


CentOS的U盘安装

采用U盘安装CentOS时,会出现 rdsosreport.txt无法保存导致无法继续安装的问题时.

在install CentOS选项时,tab一下,改为

vmlinuz initrd=initrd.img linux dd quiet
,

然后系统会告诉你U盘属于第几个分区,例如我是sdb4.

那么再次重启时,在install CentOS选项时,改为

vmlinuz initrd=initrd.img inst.stage2=hd:/dev/sdb4 quiet


,继续即可解决问题.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息