从2013开始,就一直在xx发布一些工作当中的很易错或总结性的经验积累
我本身就是linux开发工程师,用ubuntu作为办公电脑桌面几年了,也是xx的linux服务器管理员。
如果只是 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这个问题的,你可以自己想想就知道了
最近在弄静态检查,发现shell脚本也是可以被静态检查的
apt install shellcheck
即可安装shellcheck.
写完shell脚本,记得用它检查一下,能给你点建议的. 要检查现有项目的所有的脚本,
find your_project_folder -name "*.sh" | xargs -i shellcheck {}
即可.
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
就可以享受内网的高速安装了!
计算单核计算能力,一般常用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位
linux下的sublime text无法输入中文.
解决方法之一:
cd ~/.config/sublime-text-3/Packages;
git clone https://github.com/xgenvn/InputHelper
然后,然后就搞定了 ctrl+shift+z就会弹出一个input输入框,上面可以输入中文,回车后,就会进入sublime.
这种方法不是很完美. 有实践过成功的所谓完美解决方案吗?
老方案:
Linux有一个常用的操作, 就是删除所有东西但除了XX.
以前的做法是
find . -not -name 'xx' -not -name 'yy' | xargs rm -rf
来实现, 比较麻烦.
新方案:
其实shell有强化功能,
shopt -s extglob
打开glob的强化功能.
那么
rm !(xx|yy)
就可以删除除了xx和yy之外所有文件, 非常方便.
xml文档建议采用xmllint检查一下
ubuntu中
apt install php-xml
即可具有xmllint.
简单的语法检查
xmllint --noout xxxx.xml
即可完成基本检查。
mockcpp其实是个很好用的东西。
编译采用了cmake的方式。
cmake -DCMAKE_INSTALL_PREFIX=/usr/local;
make;
sudo make install
就能搞定编译安装了
问题:
系统测试中,以前为了测试单板的串口,必须在单板附近放一台主机运行测试用例对单板进行串口测试. 我大胆地想象,在不改动程序的前提下,串口数据能否通过网络走掉,这样,现场就不需要加一台主机了
解决方案:
在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就恢复了
问题:
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不加参数时, 很不好用, 杀死进程必须输入全名,
例如”python 全路径程序”启动的程序, 输入全名真让人受不了.
加参数 -f 就非常简单了, pkill -f 后面带一部分文字即可杀死!
例如, python /opt/xx/yy/zz_aa.py的进程名, pkill -f zz_
即可杀掉进程名包含zz_字符串的进程, 非常方便!
shell脚本是明文的,如果希望内容不公开,可以采用shc工具将shell变成可执行程序.
shc的原理和名字一样,就是将shell翻译为c语言,然后再编译c为可执行程序.
举例, jenkins有人希望可以按某账号提交, 可以写一个脚本,
svn ci -m "xxx" --username=yy --password=zz --non-interactive
然后变成可执行程序, jenkins调用程序即可实现.
这样,就可以做到隐蔽密码的功能。
wget是用来下载的命令,也可以下载ftp协议的东西,
举例, 单板的rom放在ftp服务器上, 我们需要一个命令获取下来, 可以采用
wget -e use_proxy=no --ftp-user=xxx --ftp-password=yyyy ftp://zzzzzzz
即可下载下来.
注意, 需要将use_proxy设置为no, 否则公司的代理服务器会无法识别你的内网ftp服务器, 从而下载不了.
本来这个参数要写在~/.wgetrc中,但是,单独在命令行中写,更为方便灵活
有了rsync, cp这种过气的指令都可以丢掉了.
rsync不仅可以本地复制,还可以远程复制. 复制的功能强大很多, 例如符号的复制, 复制进度和速度等等.
假设本地一个bin文件,需要复制到单板中, 以前的做法是必须sftp连接上后,进行cp指令. 现在可以
rsync -av ./xx.bin user@ip:remote_foldler
就可以直接复制远程设备的目录上了.
在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才能生效.
这时普通的用户也可以使用串口通信了.
登录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中, 这样是一个比较好的实践.
jenkins的bash运行时,默认带-ex参数.
-x代表每一句执行的代码都会通过+代表层次的打印出来.
-e 就非常关键了, 因为它改变了bash的特性, 默认情况, bash会执行每一行,不管每句是否成功,但加了-e, 中间其中一句出错就会退出, 改变很大.
因此,当需要bash在运行其中语句时,只要其中一句出错就退出,可以加-e参数,-x是更方便调试。
bash中,判断变量是否被定义,可以采用
if [ ! -v VAR]
注意这里VAR前面不能有$.
这种方法对4.2版本以上的bash有效
如果bash版本低, 可以采用
if [ -z ${VAR+x} ]
来判断.
注意, if [ -z $VAR ]是不准确的,
因为这种判断如果是没有定义或空字符串的情况都会返回成功.
(定义了一个变量, 如果需要取消, 采用unset VAR 即可). VAR+x这种方式,属于bash的参数拓展, 具体的可以详查资料
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 update怎么都无法下载下来时,采用
svn revert --depth infinity folder_name
再svn update folder_name
即可恢复.
如果是删除导致路径冲突,采用
svn resolved xxx_name
再更新即可.
linux的svn默认是不会将文件的执行权限上传到服务器的,导致了很多脚本checkout出来后,都必须chmod +x操作。
这种属于治标不治本。
脚本本地给予x的权限再上传是没用的,服务器会忽视x的权限。
正确的操作是
svn propset svn:executable on file.name
, 然后svn commit,这样上传的脚本下次update下来后,才会具有原生的执行权限。
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 命令吧。
X11就是X windows system 版本11的意思,用于窗口的位图显示.
linux默认都支持X11, ssh服务一般也默认支持X11转发.
那么当需要打开远程电脑的图形界面时,就不需要VNC或rdp等远程桌面, 只需要在ssh登录中加入-Y, 如
ssh -Y user_name@ip
登录后, 举例,执行firefox,那么就会弹出firefox的图形界面了.
这种方式,不需要全局桌面,只显示你需要的软件GUI, 很是方便, 也不需要额外配置什么.
这其中的原理就是利用了ssh的转发功能, X11的客户端和服务端数据都通过ssh转发实现交互.
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 -b file_name
然后输入:%!xxd
即可查看
对于统一开发环境, 代码可以放在本地, 服务器通过cifs(common internet file system)加载本地文件夹, 通过ssh在服务器上编译.
(这样可以防止代码放在服务器上,服务器挂了,导致无法工作的问题. )
操作方法:设置windows的代码文件夹为共享文件夹(注意权限!), 服务器通过
sudo mount -t cifs -o username=employee_id,password=xxxxxx,dir_mode=0777,file_mode=0777 //win_ip/share_folder server_folder
即可解决.
注意, mount 是需要root权限的
因此, 服务器的/etc/sudoers中需要加入 %xxgroup ALL=/bin/mount /bin/umount
来给xxgroup的用户赋予mount的sudo执行权限.
作为服务器管理员,需要管理多台电脑,以前的做法是,服务器需要和外网连接时,就用自己的上网认证账号登录.
现在公司做了唯一性认证,这台登录了,那台就掉线了,无法同时使用.
可以采用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代理功能。
如果一台电脑A具有更高的上网权限,而且它具有ssh服务.那么,其他电脑可以通过
ssh -fND localhost:xx_port user_A@ip_A
即可实现通过那台电脑来上网.
举例,firefox的高级-网络-设置中,选择手动代理,将除socks5以外的全部清空,socks5填入127.0.0.1 xx_port.
那么,firefox上网时,就会走那台电脑来上网,这样就可以访问更高权限的网页了
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,但是加入了链路检测。
编译:将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-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文件。
假设单板处于内网,客户无法访问单板的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隧道只支持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时,环境变量即不是来自当前用户,也不是来自root用户.
为了安全,它只留了几个最基本的环境变量,如果需要继承当前用户的环境变量,需要加 -E
例如,ubuntu使用 sudo add-apt-repository ppa:
添加源时,往往会失败,根本原因就是没有继承当前用户的proxy的环境变量,导致连接不了网络,加入-E,就能正常添加了.
其他程序类似问题也是如此解决.
至于sudo echo $XX, 能打印输出XX的内容,本质是shell在运行这个时,直接替换了XX对应的内容,如果sudo要执行的是一个程序或脚本,就会发现环境变量进不去的问题.这时就要使用-E了
软件安装包一般会有自己的库和头文件路径,一般不需要记忆,最好通过
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的问题了
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,比较友善
周末停电,单板被重新分配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信息。
为什么linux要反对使用我们用滥了的typedef。
linux内核规范认为,typedef出来的类型,会降低可读性,没人知道foo_t这个类型到底是结构体还是指针还是联合体。
对我而言,我看中的是另外一点,就是struct foo foo这种定义是合法的。struct foo foo第一个foo是在tag空间里,后面的foo是在变量空间里,所以重名合法,这可以解决结构体命名和它对应的变量怎么命名区分的烦人问题。然而,typedef出来是type,是不允许和变量重名的,自己解决命名的问题吧。
linux中的周期或定期执行的任务,你还在自己写程序计时实现吗?
可以使用linux的cron指令。
cron是一个专门负责周期,定期执行任务的指令。使用它有如下好处:
1.可以实现你能想到的各种周期执行方式;
2.简化代码,代码不用再重复制造轮子;
3.cron的设计考虑的很周全,如,时钟被改变的情况等情况都考虑进去了;
4.节省cpu,我们的代码都是硬累加变量,不断地判断,而cron采用sleep的唤醒方式,尤其是有多个周期任务时,自己实现的代码每个都要自己不断累加变量,而cron是统一判断时间,这样可以节省很多cpu时间;
5.我们的程序自己执行任务几乎都是阻塞的,cron通过多次fork的方式,没有阻塞问题。
单板本身就有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(0),exit(1)的使用,很多人只关注了它退出程序的作用,却忽视了中间数字的作用。中间的数字,是程序退出时的返回值。通过 echo $?
指令,可以获取上一次程序或命令执行的返回值。
默认情况下,程序成功运行时,会返回0,失败会返回大于0的值。但人为的加入exit(x),当程序通过你的exit(x)退出时,就会返回x,根据x就可以知道在哪里退出了。
另外,echo $?
不能连续使用,因为第一次执行echo $?
时,这条指令是成功运行的,所以值就会被修改为0,下次echo $?
就只能拿到上次echo $?
的返回值0 了
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 表示进入人机交互界面. 这样就实现了另一种免输入密登录单板的途径了
关于进程在后台运行的问题.一般人的操作都是在程序后面加 &.
这样有个局限,就是终端关闭了.这个后台运行的程序也会被关闭.
通过pstree
指令可以看到上述操作,终端是作为父进程,关闭终端,会收到SIGHUP的信号,SIGHUP会继续传递给子进程,这就是为什么终端关闭,加了&也会死掉的原因.
可以执行
nohup your_program &
也就是开头多加nohup就行了,意思是不让SIGHUP传递给子进程.
原来被执行的程序是沿用了终端的stdout,stderr的, 终端关闭,执行程序也就无法输出了,因此,nohup还会做一件事,就是断了和终端的联系,所以nohup会让程序的输入,输出重定向,自然终端上就不会显示输出了.
我们单板的stack上限是8M,和PC版的linux一样。
如果stack里的数组(如函数的局部结构体数组)会存储比较多的东西时,就要检查一下是否会超过8M了。
以前在解析工具中碰过超出了8M的stack上限的问题。
在单板中,没有ulimit
指令供使用。需要用库函数获取,
#include
struct rlimit rl;
getrlimit(RLIMIT_STACK, &rl);
后 rl.rlim_cur 就是系统的stack上限了,检查一下stack里的巨型数组是否超过它,是非常有必要的。
如果一个程序需要接收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
来查看动态库的依赖关系,也可以查看交叉编译后的执行程序的依赖关系。
在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优化发现内存有不同类型指针同时指向时,会产生告警提示
linux的zip命令,默认会将路径信息加入压缩包中,解压后会保留原文件路径的文件夹,加入-j即可去掉文件夹信息(junk),如,
zip -j xxxx.zip xxxx.xml
.另外,zip不像bzip2压缩后会删除源文件,需要额外rm一下。
linux在新建一个文件时,都有一个默认的权限,这个默认权限可以通过umask
指令进行修改。
umask可以查看现在的权限,如0002.意味着other的w权限会失去。
注意这里是umask,和mask的逻辑正好相反。umask 0000,意味着不屏蔽权限。
linux的inotify机制。如果需要监视文件夹或文件,例如文件夹新增、删除、修改文件,文件内容改变,属性改变,时间改变,是否被打开、关闭等的需求,都可以使用inotify机制。
这是一种源于linux内核和文件系统的基于事件的机制。相比古董式的轮询方法,它具有节省cpu资源和非延迟的特性。推荐使用。
linux的bash脚本如果需要嵌入python语言实现更复杂的实现,只需要python -c ‘xxxxx’即可,xxxx可以是多行的python代码。
举例
echo "good"
python -c 'print("bad");print("normal")'
这对于拓展bash脚本非常实用。
由于ctrl+s是绝大多数软件的保存快捷键,有时xshell处于选中状态时,不小心按到ctrl+s,那个窗口就无法操作了。
最笨的方法是关掉重新连接。
其实,在linux中,ctrl+s是锁定屏幕的意思,屏幕没有动,但是键盘的操作仍然是继续的。
解决方法:按下ctrl+q就可以解锁了。
在/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”字符串的输出。非常实用
一个常见的易错点,linux中很多人会用 system("cd /xxx/xxx")
试图改变当前进程的路径,其实这是无效的,因为system会新开一个进程执行shell指令,完成后返回,因此,cd改变路径并不会影响当前进程,这就是无效的原因。
进程如果需要改变路径,应该使用chdir
函数。
如果需要在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中如果需要查看内存的值,可以使用x指令, x/n addr
表示打印addr开始的n个单位的内存值,
嵌入式arm单板CSU的单位为byte,pc机的linux系统为int。
如果不想采用默认单位,
则x/nb
输出n个byte, x/nw
输出n个int。
当使用sed进行多关键词匹配时,如关键词为X,Y,Z,则可以
sed -n "/X/{/Y/{/Z/p}}"
即如果需要新增关键词时,规律为在p在左边加上{/key_word/,右边加上}
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功能很强,但也不好理解。
前段时间做了一个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缩进的方法:
全文自动缩进gg=G,gg为回到第一行,=为自动缩进,G表示最后一行。
局部缩进可以,n==,n表示光标下的连续n行自动完成缩进,省略n时,为当前行执行。
>>为indent,<<为unindent,==为auto indent。局部自动缩进,也可mG=nG。
vim处理括号里内容可以采用,[d,y,v]i[符号],例如,一个光标在一个括号内,di(或di)都可以将括号里的内容剪切掉,如果需要加上括号,将i改为a即可,同理可推导其他组合。如果需要将某些行移动到X行的后面,可以,: 3,23 m 45 ,m即move的意思。
在Ubuntu下如果需要串口连接CSU进行调试,可以在软件中心直接安装serial port terminal的软件,注意,这个玩意的运行名称居然叫gtkterm,而且sudo gtkterm才能打开串口。因为串口属于dialout组,sudo肯定可以打开,否则需要将自己加入dailout中,设置波特率为115200后就可以像windows下的xshell一样调试CSU了。
当某个文件夹只有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路径下的文件夹名称为中文,输入非常不方便,可以采用 export LANG=en_US && xdg-user-dirs-gtk-update
变成英文文件夹名称。
也可以一劳永逸的解决:将 /etc/default/locale
里的内容改为
LANG="en_US.UTF-8"
LANGUAGE="en_US:en"
注销,重新登入即可。
对于docker .... bash xxx.sh
这种运行xxx.sh脚本的方式,环境量是个问题。
这种方式的环境量不等于你采用docker -it bash
进入的人机交互界面。
很多在.bashrc或profile甚至在/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总是不生效。后来发现,是因为我采用sh file_name 或./file_name的方式运行脚本。
这种方式本质是新建一个进程,再执行,当前打开的shell当然无法使用alias或export的成果了。
正确方法为: source file_name
或 . file_name
.是source的简写,一样的效果。source的作用是在当前的shell执行脚本,所以export和alias会生效。
xshell在部分场合下,按退格键,会出现奇怪的字符,无法实现删除的效果。
打开窗口属性,找到“键盘”,将BACKSPACE键序列改为backspace选项即可。
安卓上是可以跑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 -u user,password sftp://csu_ip <cd remote_directory lcd local_directory put file_name1 get file_name2 bye EOF
注解: EOF是表示结束的标志,不一定用这个
put就是上传,get就是下载
如果基于bash4,可以采用新语法:
exec command &>> xx.log
无需使用老款的(2>&1)
新语法的&就是将stderr和stdout都重定向的意思。
(>>是追加的意思)
当缺少一个库时,如何知道需要安装什么,才能拥有这个库呢?
Centos下有yum whatprovides
ubuntu下却没有相同的东西.
但可以有如下两个方法解决:
1. http://packages.ubuntu.com/ 里查找
2. 使用apt-file search 查找.
都能解决库的所属问题.
ubuntu通过
apt install arcanist
即可完成pha的客户端必要工具安装.
这里有个坑,就是ubuntu16.04仅用这个还不够.
否则在执行arc diff时,会出现包含”SimpleXMLElement”关键字的一些错误.
坑了很久,才发现增加
apt install php-xml
即可补全这个必要的库.
RF的ride在__init__.py文件限制了wxpython只能使用2.8。
ubuntu16.04里的wx都是3.0以上的版本,装回2.8很是麻烦.
其实,只要手动修改__init__.py,在 支持版本那加入”3.0”即可。
重新运行ride.py,正常执行.
问题:
在ubuntu 64位的系统中,如果有32位的应用程序需要在64位,那怎么执行呢?
解决:
可以根据缺失的库名加:i386来安装。
例如:
sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386
安装完后,依赖这些库的32位程序就可以跑起来了.
忍不住升级了ubuntu. 升级到15.10后,桌面没有panel.
ctrl+alt+t可以打开终端, 输入unity, 打印信息发现是compiz出问题了.
dconf reset -f /org/compiz/
即可恢复compiz的设置,
注意这里最后的斜杠是一定要的
(不同的软件,对最后的斜杠处理逻辑是不一样的).
这时, 再次通过
setsid unity
打开桌面即可出现久违的panel.
setsid的意思是新起的进程和父进程无关,这样,shell终端关闭也不会影响unity桌面.
setsid的用法和nohup以及& disown的效果类似.
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默认安装有remmina,该软件可以远程桌面windows,非常好用
问题:
在Centos上安装jenkins,如果jenkins上执行sudo指令,会出现“Sorry, you must have a tty to run sudo”的错误.
原因:
在于CentOS的/etc/sudoers
里有一句“Defaults requiretty”。
这句话要求sudo的运行必须有一个tty,但实际上又没有多大的安全作用(ubuntu已经没有这句了)。
解决:
将这句注释掉, 以后执行sudo就不会有这个错误了。
问题:
执行程序少共享库,举例,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了
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
采用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
,继续即可解决问题.