随机记录一些Linux常用命令使用笔记。

rsync:文件同步

rsync 来源 目标 --archive --acls --xattrs --verbose --progress --one-file-system

需要同步并删除时,加--delete参数

输出重定向

终端默认打开3个fd:

  • 0:标准输入
  • 1:标准输出
  • 2:标准错误

>dev/null 2>&1:输出重定向到null,错误重定向到输出(此时输出是null,所以错误输出到了null),不打印输出和错误

2>&1 >/dev/null:错误重定向到输出(此时输出是终端,所以错误输出到了终端上打印),输出重定向到null,只打印错误

2>&-:关闭标准错误描述符。The general form of this one is M>&-, where "M" is a file descriptor number. This will close output for whichever file descriptor is referenced, i.e. "M".

2>/dev/null:The general form of this one is M>/dev/null, where "M" is a file descriptor number. This will redirect the file descriptor, "M", to /dev/null.

2>&1:The general form of this one is M>&N, where "M" & "N" are file descriptor numbers. It combines the output of file descriptors "M" and "N" into a single stream.

|&:This is just an abbreviation for 2>&1 |. It was added in Bash 4.

&>/dev/null:This is just an abbreviation for >/dev/null 2>&1. It redirects file descriptor 2 (STDERR) and descriptor 1 (STDOUT) to /dev/null.

>/dev/null:This is just an abbreviation for 1>/dev/null. It redirects file descriptor 1 (STDOUT) to /dev/null.

screen/tmux

如何将进程移到screen/tmux:

  1. Ctrl+Z进程
  2. bg恢复进程在后台运行
  3. 解除从属关系disown %1
  4. 启动一个screen/tmux
  5. 查找进程PID
  6. 执行reptyr -T pid,将进程移到该screen/tmux

disown 命令: https://gnu-linux.readthedocs.io/zh/latest/Chapter06/sshBackstage.html

SSH连接后自动打开Tmux,同时避免与VSCode远程开发冲突 https://zhuanlan.zhihu.com/p/346594276

tmux new -s 7580:创建会话名称为7580的会话,最好不要纯数字名称 ./umbuild_7580.sh > stdout.txt 2>&1 &:后台执行编译程序 tmux detach:会话分离

tmux ls:列出会话列表 tmux attach -t 【会话编号/会话名称】:重新进入会话 jobs

  • Done:后台程序执行完成
  • Running:表示正在运行
  • Stopped:表示已经被挂起,那么不再会被调度,查看下编译输出,可能已经error了
  • kill %job-id
  • fg %job
  • bg %jog,一般终端会一直输出,一般使用快捷键Ctrl+Z

该方法可以保证编译不因为网络断开而终止 当关闭ssh窗口后重新连接,虽然无法重新进入会话,但可以通过tail stdout.txt查看最新编译进展,编译成功后stdout.txt最后一行会为0

diff命令:比较目录/文件差异

对比2个目录有哪些文件不一样,从diff手册页:

-q仅报告文件是否不同,而不是差异的细节。
-r比较目录时,递归比较找到的所有子目录。

示例命令:

diff -qr dir1 dir2

cp命令

当需要拷贝多个文件并且需要保留源文件的目录树结构时, 如果源目录的文件比较纯净,没有其他相关的文件或目录时, 我们只需要执行

cp -r [src_dir] [dst_dir]

否则,只能执行

cp --parent [src_file] [dst_dir]

sudo命令执行很慢

1、首先如果当用登录的用户名不在"/etc/sudoers"文件中,是不能执行sudo命令的。可以用root身份手动修该文件,把当前登录用户名加入该文件中。

2、用"hostname "命令查看当前主机的主机名称。例如,该命令返回"ubuntu ".

3、用vi打开"/etc/hosts"文件,并将"ubuntu"加入到 "127.0.0.1"这行中。

例如:

127.0.0.1       localhost      ubuntu

原因是sudo认证时,pam的代码会访问到域名服务器,如果你的hostname不被/etc/hosts记录,且/etc/resolv.conf里的域名服务器无法正确解析你的hostname,将会导致挂起30秒。

https://bugzilla.redhat.com/show_bug.cgi?id=479464

https://superuser.com/questions/429790/sudo-command-trying-to-search-for-hostname

https://askubuntu.com/questions/322514/terminal-command-with-sudo-takes-a-long-time/458057#458057

sshpass命令:ssh自动输入密码

sudo apt install sshpass

# quick ssh connect
alias pon1='sshpass -p "pon_123" ssh um_pon@192.168.133.22'

alias pon2='sshpass -p "ztc@321n" ssh gztc@192.168.133.22'

cut命令

cut 命令对指定文件的内容的每一行进行截断,并将截断后的所有内容(或部分内容)输出到标准输出。

usage: cut -b list [-n] [file ...]  
cut -c list [file ...]  
cut -f list [-s] [-d delim] [file ...]

如果不指定 File,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。

参数:

  • -b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。(注意:一个空格算一个字节,一个汉字算三个字节)
  • -c :以字符为单位进行分割。(中文字符和空格都算一个字符)
  • -d :自定义分隔符,默认为制表符。
  • -f :与 -d 一起使用,指定显示哪个区域。
  • -n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的范围之内,该字符将被写出;否则,该字符将被排除

dd:磁盘读写命令

通过dd生成指定内容的文件

在某些情况下,可能会用到全为某个值的 bin 文件,可使用 dd 命令配合 /dev/zero 这个特殊的文件设备,来生成全为 0x00 的 bin 文件,而后在使用 tr 命令,替换0x00 为 0xFF,命令如下所示:

dd if=/dev/zero  bs=1M count=2 | tr "\000" "\377" > test.bin

命令生成全为 0xFF 的 2MB 的 bin 文件。 其中 \377 为八进制数,即 0xFF。

在生成 test.bin 文件后,使用命令:

echo hello | dd bs=512 seek=2 conv=notrunc of=test.bin

可将 hello 写入到 test.bin 文件的 0x400 地址处,文件大小不变。 使用命令查看:

hexdump test.bin -n 100 -s 1008 -C

在新生成的 test.bin 中,从 0x200 地址开始,截取 2K 文件,生成 test1.bin 文件:

dd if=test.bin conv=notrunc bs=512 skip=1 count=4 of=test1.bin
  1. dd命令可以轻易实现创建指定大小的文件,如

dd if=/dev/zero of=test bs=1M count=1000

在当前目录下会生成一个1000M的test文件,文件内容为全0(因从/dev/zero中读取,/dev/zero为0源),但是这样为实际写入硬盘,文件产生速度取决于硬盘读写速度,如果欲产生超大文件,速度很慢。在某种场景下,我们只想让文件系统认为存在一个超大文件在此,但是并不实际写入硬盘

则可以

dd if=/dev/zero of=test bs=1M count=0 seek=100000

此时创建的文件在文件系统中的显示大小为100000MB,但是并不实际占用block,因此创建速度与内存速度相当,seek的作用是跳过输出文件中指定大小的部分,这就达到了创建大文件,但是并不实际写入的目的。当然,因为不实际写入硬盘,所以你在容量只有10G的硬盘上创建100G的此类文件都是可以的。

  1. 随机生成1百万个1K的文件 seq 1000000 | xargs -i dd if=/dev/zero of={}.dat bs=1024 count=1

使用dd进行磁盘读写速度测试

一般情况下,我们都是使用dd命令创建一个大文件来测试磁盘的读写速度。但是,很多人都存在一个误区,以为dd命令显示的速度就是磁盘的写入速度,其实这是不然的。我们分析一下dd命令是如何工作的。

  1. dd if=/dev/zero of=/xiaohan/test.iso bs=1024M count=1

这种情况下测试显示的速度是dd命令将数据写入到内存缓冲区中的速度,只有当数据写入内存缓冲区完成后,才开始将数据刷入硬盘,所以这时候的数据是无法正确衡量磁盘写入速度的。

  1. dd if=/dev/zero of=/xiaohan/test.iso bs=1024M count=1;sync

这种情况下测试显示的跟上一种情况是一样的,两个命令是先后执行的,当sync开始执行的时候,dd命令已经将速度信息打印到了屏幕上,仍然无法显示从内存写硬盘时的真正速度。

  1. dd if=/dev/zero of=/xiaohan/test.iso bs=1024M count=1 conv=fdatasync

这种情况加入这个参数后,dd命令执行到最后会真正执行一次“同步(sync)”操作,所以这时候你得到的是读取这128M数据到内存并写入到磁盘上所需的时间,这样算出来的时间才是比较符合实际的。

  1. dd if=/dev/zero of=/xiaohan/test.iso bs=1024M count=1 oflag=dsync

这种情况下,dd在执行时每次都会进行同步写入操作。也就是说,这条命令每次读取1M后就要先把这1M写入磁盘,然后再读取下面这1M,一共重复128次。这可能是最慢的一种方式,基本上没有用到写缓存(write cache)。

总结:

建议使用测试写速度的方式为:

dd if=/dev/zero of=/xiaohan/test.iso bs=1024M count=1 conv=fdatasync

建议使用测试读速度的方式为:

dd if=/xiaohan/test.iso of=/dev/zero bs=1024M count=1 iflag=direct

*注:要正确测试磁盘读写能力,建议测试文件的大小要远远大于内存的容量!!!

curl命令

curl使用指定ip请求https

一般地,在 curl 中,如果想以指定的 ip 来请求一个域名地,可以使用 curl http://127.0.0.1/example -H 'Host: www.example.org'
这种指定 Host 头的做法,但这在 https 中可能会失败,显示 no alternative certificate subject name matches target host name '127.0.0.1

显然这是由于 curl 将 https://127.0.0.1 里的 127.0.0.1 而不是 Host 头用于验证证书的 subject name,而这个 ip 如果不在证书的 subject names 中,
将会导致证书验证失败。

一般的解决方案,我们可以在 /etc/hosts 或 dnsmasq 用指定 ip 解析这个域名,但这改起来显示比较繁琐。还好在 curl 7.21.3 中,提供了一个 --resolve <host:port:address>'
参数,让我们可以很方便地将域名解析到指定的 ip 上,例如上面的请求可以改成 curl --resolve 'www.example.org:443:127.0.0.1' https://www.example.org

curl 有一个 --resolve 参数可以达到类似于 hosts 文件的效果。用 -H 来指定 Host 的话,在 https 请求时要记得配合 -k / —insecure 绕过域名检查。

Linux 中使用 curl 代替 telnet 测试端口是否连通curl

在一些没有装有telnet的机器并且还没有访问外网的权限下,想要测试内网某个ip下的端口是否可以被连接,可以使用curl telnet://

curl -vv telnet://192.168.1.101:8080

显示Connected表示可以连接,使用Ctrl+C退出。

$ curl -vv telnet://192.168.1.101:8080
* About to connect() to 192.168.1.101 port 8080 (#0)
*   Trying 192.168.1.101...
* Connected to 192.168.1.101 (192.168.1.101) port 8080 (#0)

一直显示Trying表示连接不通,使用Ctrl+C退出。

$ curl -vv telnet://www.baidu.com:443
* About to connect() to www.baidu.com port 443 (#0)
*   Trying 112.80.248.75...

curl杂项

curl不关闭打印信息时会另起进程

curl命令去除所有的状态信息:curl -s [URL] -o [path]

curl命令不使用缓存:curl -H 'Cache-Control: no-cache' http://www.example.com

模拟post请求: curl -H "Content-Type: application/json; charset=utf-8" -X POST -d '{"jsonrpc":"2.0","method":"hgmanager.STBSNAndMAC","params":{"mac":"00:19:F0:FF:FD:36","sn":"009901FF0018100000010019F0FFFD36"}}' 192.168.1.1:61998

使用 curl 上传一张图片:

curl -X POST -d "smfile=/Users/ashfinal/2.png" https://sm.ms/api/upload

指定 curl 的 UA:

curl --user-agent "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" https://www.bing.com/az/hprichbg/rb/BMXTunnel_ZH-CN11405649743_1920x1080.jpg -O

curl (可直接发送格式化请求例如json),提交json数据需要加header,否则需 'json={"phone":"13521389587","password":"test"}’

curl -H "Content-type: application/json" -X POST -d '{"phone":"13521389587","password":"test"}' http://domain/apis/users.json

普通请求:curl $URL -d "2880[]=105&pid=2880&p=最佳&count=1&receipt=1&poll=投票"

请求 GitHub Trend 数据

curl -G https://api.github.com/search/repositories --data-urlencode "sort=stars" --data-urlencode "order=desc" --data-urlencode "q=language:java"  --data-urlencode "q=created:>`date -v-7d '+%Y-%m-%d'`" > tmp.json

curl和bash

https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-bash-server-side/

使用 curl | bash是不安全的,bash如果执行过程中有延时,会被服务端检测到,从而发送恶意数据。

# 简单辨别:服务端的延时检测不一定是3秒,也不一定只检测一次,所以还是不能 curl | bash
curl https://example.com/setup.bash | cat
curl https://example.com/setup.bash | (sleep 3; cat)

wget命令

wget关闭进度输出:

wget -q [URL] -O [path]

wget --header="Cache-Control: no-cache"

wget -o log

wget发post请求:wget --post-data="user=user1&pass=pass1&submit=Login" http://domain.com/path/page_need_login.php

crontab:设置定时任务

cron语法

cron.png

crontab修改编辑器

方法一:通过select-editor 使用 select-editor 命令,随便选一个编辑器,然后在home目录将生成一个 .selected_editor 文件

# Generated by /usr/bin/select-editor
# SELECTED_EDITOR="/usr/bin/vim.tiny"               SELECTED_EDITOR="/usr/bin/nvim"

修改该文件即可

方法二:通过环境变量 环境变量可以设置VISUALEDITOR,两个任何一个都可以,如我想在编辑crontab时使用vim打开可以这么做

VISUAL=vim crontab -e  

或者也可以这样

EDITOR=vim crontab -e  

当然,你也可以添加到/etc/profile里,这样每次使用crontab前不需要再声明环境变量了

export EDITOR=vim
export VISUAL=vim

dig:DNS查询

Dig是一个在类Unix命令行模式下查询DNS包括NS记录,A记录,MX记录等相关信息的工具。

dig github.com @8.8.8.8

du:统计目录/文件占用磁盘大小

du -sh

-s,--summarize:display only a total for each argument, -s这个参数的作用就是仅显示总计,即当前文件夹的大小。

-h, --human-readable:print sizes in human readable format (e.g., 1K 234M 2G)

-c, --total:produce a grand total,使用-c选项,你可以在输出的最后一行看到总的磁盘使用情况,包括所有子目录

[modao@modao qemu]$ du -shc
7.5G    .
7.5G    total
[modao@modao qemu]$ du -sh
7.5G    .

du -sh * *可以将当前目录下所有文件的大小给列出来

要将这些列出来的文件按照从大到小的方式排序:du -s * | sort -nr,排序时不能加-h参数,否则排序结果可能不对

df:查看磁盘使用情况

df -h

grep:检索文件内容

遇到的问题:

用grep -c “xxx字符”得到的是行数,如果一行中有多个匹配到的字符,只会算作一个

解决方法:

使用grep -o "xxx字符"按行显示出所有的匹配结果,然后再用grep -c "xxx字符"来计算行

grep字符串全匹配:grep -w

grep命令查找多个字符串:grep -E 'pattern1|pattern2' file

linux下使用grep在当前目录下搜索所有文件中含有的字符串:grep -r [搜索内容]

kill:杀进程

kill -9 pid

可以使用其它信号,一般用9,代表结束进程

killall pid_name

pid:可能选择有以下四种

  1. pid大于零时,pid是信号欲送往的进程的标识。
  2. pid等于零时,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
  3. pid等于-1时,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
  4. pid小于-1时,信号将送往以-pid为组标识的进程。

当需要把 linux 下符合某一项条件的所有进程 kill 掉,又不能用 killall 直接杀掉某一进程名称包含的所有运行中进程(我们可能只需要杀掉其中的某一类或运行指定参数命令的进程),这个时候我们需要运用 ps, grep, cut 和 kill 一起操作。

杀掉所有含有关键字"stress"的进程:

ps -ef | grep stress | grep -v grep | cut -c 9-15 | xargs kill -9

  • "ps -ef" 是linux里查看所有进程的命令。这时检索出的进程将作为下一条命令"grep stress"的输入
  • "grep stress" 的输出结果是,所有含有关键字"stress"的进程
  • "grep -v grep" 是在列出的进程中去除含有关键字"grep"的进程
  • "cut -c 9-15" 是截取输入行的第9个字符到第15个字符,而这正好是进程号PID
  • "xargs kill -9" 中的 xargs 命令是用来把前面命令的输出结果(PID)作为"kill -9"命令的参数,并执行该命令。"kill -9"会强行杀掉指定进程。

另一种方法,使用awk

ps x | grep gas | grep -v grep | awk '{print $1}' | xargs kill -9

驱动模块相关命令

insmod:加载驱动

modprobe:加载驱动,并自动加载依赖驱动

rmmod:卸载驱动

lsmod:查看系统中所有已经被加载了的所有的模块以及模块间的依赖关系,可能还可以看驱动大小

modinfo:获得模块的信息

cat /proc/modules:能够显示驱动模块大小、在内核空间中的地址

cat /proc/devices:只显示驱动的主设备号,且是分类显示

/sys/modules:下面存在对应的驱动的目录,目录下包含驱动的分段信息等等。

ls /sys/bus

ls /dev

tree:打印目录结构

tree命令生成目录结构保存为 html:tree -H . > test.html

方便生成目录

tree --charset utf8 -H file:///Users/ashfinal/Downloads ~/Downloads -o ~/tmp.html

strip:去除可执行文件的符号表

strip:简单的说就是给文件脱掉外衣,具体就是从特定文件中剥掉一些符号信息和调试信息,使文件变小。

对一个可执行文件,可以使用file查看其基本信息,可以使用nm查看其符号信息。

使用strip对可执行文件处理后,文件大小会变小,nm查看不到符号信息。

strip不仅仅可以针对可执行文件, 还能针对目标文件和动态库等。在实际的开发中,经常需要对动态库.so进行strip操作,减少占地空间。 而在调试的时候(比如用addr2line),就需要符号了。 因此,通常的做法是:strip前的库用来调试,strip后的库用来实际发布,他们两者有对应关系。一旦发布的strip后的库出了问题,就可以找对应的未strip的库来定位。

ps:查看进程

相关进程状态:

D 不可中断,Uninterruptible sleep (usually IO) R 正在运行,或在队列中的进程 S 处于休眠状态 T 停止或被追踪 Z 僵尸进程 W 进入内存交换(从内核2.6开始无效) X 死掉的进程 < 高优先级 N 低优先级 L 有些页被锁进内存 s 包含子进程 + 位于后台的进程组; l 多线程,克隆线程multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

mount:文件系统挂载命令

查看系统挂载情况:

  • cat /proc/mounts
  • mount

修改/etc/fstab 默认挂载权限

mount -a:根据fstab挂载文件系统

重新挂载根目录,加读写权限 mount -o remount rw /

ping:发icmp包判断网络是否可达

-i <间隔秒数> 指定收发信息的间隔时间。

-c <完成次数> 设置完成要求回应的次数。

-I <网卡接口> 使用指定的网络接口送出数据包。

-q 不显示指令执行过程,开头和结尾的相关信息除外。

-v 详细显示指令的执行过程。

-w 在 deadline 毫秒后退出。

-W 在等待 timeout 毫秒后开始执行。

-c是指定总的发包数,-w是指定总的发包时间

ping -i 0.2 baidu.com

ping: cannot flood; minimal interval allowed for user is 200ms

如果要使用0.1s,则需要以root用户身份运行

fping:比普通ping好用

普通ping,在用-c指定包数为1时,且在目标不可达时,需要较久才能返回结果。这时候fping可能可以派上用场。

fping一般需要使用包管理安装。

与ping相比,fping可能是更好的工具

  • fping与ping的不同之处在于,可以在命令行上指定任意数量的目标,或者指定包含要ping的目标列表的文件
  • fping不会发送到一个目标,直到它超时或答复为止,它会发送ping数据包并以循环方式移至下一个目标
  • 与ping不同,fping是要在脚本中使用的,因此其输出旨在易于解析

find命令

  1. 查找并删除文件:find . -type f -name "filename" -delete,可以添加-depth 1指定递归深度
  2. find使用正则匹配:find . -regex ".*/[a-z0-9]\{32\}\.jpg" -exec mv {} ~/Desktop/ \;,将符合条件的图片移动到桌面
  3. 分别统计文件行数:find ~/.hammerspoon -type f -name "*.lua" -print0 | xargs -0 wc -l
  4. find配合chmod批量修改文件权限
    • 文件:find . -type f -exec chmod 644 {} \;
    • 目录:find . -type d -exec chmod 744 {} \;

fc-list命令:查看字体列表

列出中文字体:fc-list :lang=zh-cn

简短地列出中文字体:fc-list -f "%{family}\n" :lang=zh

shred命令:删除文件前覆盖文件内容

只是删除文件的话,文件内容其实还是保存在磁盘上,可以通过特殊工具读回。shred工具则会通过随机写入数据的方式对文件内容进行覆盖。

默认使用(覆盖文件内容三次):shred FILEPATH

指定覆盖次数:shred -n 1 FILEPATH

覆盖完后直接删掉文件:shred -u FILEPATH

可以设置一个alias:alias rm='shred -u'

gpg命令:文件加密

一般使用对称算法来加密文件:gpg --symmetric ${file}

这会产生一个 ${file}.gpg 的文件就是加密后的文件,但是需要注意的是,原始文件 ${file} 依然存在,不会被删除.

指定加密算法:gpg --symmetric --cipher-algo AES256 ${gpg_file}

指定输出文件

  • 加密:gpg -o ${gpg_file} ${file}
  • 解密:gpg -o ${file} ${gpg_file}