Shell 常用指令 | 系统开发

本文列举了一些常用的 shell 指令。

字符串处理(awk)

1
2
# 打印列信息
cat bench_log.txt | grep "Time used" | awk '{ print $(NF-1) }' # $NF 表示倒数第一列,$(NF-1) 表示倒数第二列
1
2
# 求均值
cat bench_log.txt | grep "Forward time cost" | awk '{ sum+=$(NF-1) } END { print "Average = ", sum/NR }'
1
2
# 分割路径
name=$(echo $path | awk -F "/" '{print $NF}')

字符串替换(sed)

1
2
sed -i "s/xxx/yyy/g" ${file_path} # Linux
sed -ie "s|xxx|yyy|g" ${file_path} # macOS

批量处理(xargs)

1
2
# 批量解压
ls *.tar.gz | xargs -n1 -I {} tar -xzvf {} # 使用 -I 指定一个替换字符串 {},这个字符串在 xargs 扩展时会被替换掉,当 -I 与 xargs 结合使用,每一个参数命令都会被执行一次;-n 后面加次数,表示命令在执行的时候一次用的 argument 的个数,默认是用所有的
1
2
3
4
5
# 导出依赖库列表并拷贝
dep_list=$(ldd test_bin | awk '{if (match($3,"/")){ print $3 }}' | grep -v "^/lib64" | grep -v "^/lib")
mkdir lib
printf $dep_list | xargs -n1 -I {} cp {} ./lib
tar -czvf lib.tar.gz lib

解压与压缩

  • 压缩
1
2
3
4
5
6
7
8
9
10
11
# 将目录里所有 jpg 文件打包
tar -cvf pack.tar *.jpg

# 将目录里所有 jpg 文件打包后,并且将其用 gzip 压缩,生成一个 gzip 压缩过的包,命名为 pack.tar.gz
tar -czf pack.tar.gz *.jpg

# 将目录里所有 jpg 文件打包后,并且将其用 bzip2 压缩,生成一个 bzip2 压缩过的包,命名为 pack.tar.bz2
tar -cjf pack.tar.bz2 *.jpg

# 将目录里所有 jpg 文件打包成后,并且将其用 compress 压缩,生成一个 umcompress 压缩过的包,命名为 pack.tar.Z
tar -czf pack.tar.Z *.jpg
  • 解压
1
2
3
tar -xvf pack.tar
tar -xzvf pack.tar.gz
tar -xjvf pack.tar.bz2

网络调试

  • 测试 http 接口

    1
    curl -kv http://127.0.0.1:8080/xxx/yyy -H'Content-Type: application/json' -d'{"name": tom}' | json_pp
  • 抓包

    1
    tcpdump -i any port 8000 -AAA -nnn
  • 查看端口监听

1
netstat -tunlp | grep <port>
1
2
lsof -i :<port>
pwdx <pid>

查看文件

  • 监视文件变化

    1
    tail -F log_file.txt
  • 查找文件内容

    1
    grep 'content' -r file_name.txt
  • 查看进程工作目录

    1
    pwdx pid

GDB

  • GDB 带参数启动程序

    1
    gdb --args ./bin_file --flagfile flag_file.conf
  • GDB 调试已有进程

    1
    attach -> break -> continue -> send request -> print
  • GDB 一次打印多个值

    1
    print {v0, v1, v2}
  • GDB 一次执行多个命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (gdb) next;p num_caches
    Invalid character ';' in expression.
    (gdb) define myfun
    Type commands for definition of "myfun".
    End with a line saying just "end".
    >next
    >p num_caches
    >end
    (gdb) myfun
    731 cpus[j].dcache->owner = (struct godson2_cpu *)&cpus[j];
    $4 = 3

LLDB

  • 捕捉异常
1
2
3
4
# break on all exceptions
breakpoint set -E c++
# break on a specific exception
breakpoint set -F std::range_error
  • 调试 Python 脚本
1
2
lldb
platform shell python3 xxx.py

valgrind 检测内存泄漏

1
valgrind --log-file=memcheck.log --tool=memcheck --leak-check=full --show-leak-kinds=all $bin

查看库内容

  • Linux
1
2
3
4
5
6
# 静态库
ar -t xxx.a # 查看包含了哪些 .o
nm --demangle xxx.a # 查看符号

# 动态库
nm --demangle xxx.so # 查看符号
  • Android
1
2
3
4
5
6
# 静态库
nm --demangle xxx.a # 查看符号

# 动态库
objdump -x ./main | grep NEEDED # 查看依赖
nm -D -C xxx.so # 查看符号
  • macOS & iOS
1
2
3
lipo -info xx.dylib/xxx.a # 查看架构
nm -C xxx.dylib/xxx.a # 查看符号
otool -L xxx.dylib/xxx.a # 查看依赖

查找

  • 查找文件
1
find . -name "*" | grep ${find_file_name}
  • 查找文件内容
1
grep -rn "${find_content}" *

查看进程信息

  • ps 自定义显示列并排序
1
ps aux pid,user,pcpu,pmem,cmd --sort -pmem,-pcpu

通过名称批量杀死进程

1
killall $full_name
1
pkill $partial_name
1
ps aux | grep $partial_name | awk '{print $2}' | xargs kill -9

查看系统信息

  • 查看物理 CPU 个数
1
grep 'physical id' /proc/cpuinfo | sort -u
  • 查看每个物理 CPU 的物理核心数量
1
grep 'core id' /proc/cpuinfo | sort -u | wc -l
  • 查看本机所有逻辑 CPU 核心个数(包括通过超线程技术增加的逻辑 CPU)
1
grep 'processor' /proc/cpuinfo | sort -u | wc -l

docker

  • 启动镜像
1
docker run -it -p $host_port:$container_port --network=host -v $host_path:$container_path $image_id bash
  • 带 CUDA 环境启动镜像
1
docker run -it --runtime=nvidia -e NVIDIA_DRIVER_CAPABILITIES=all $image_id bash
  • 修改镜像
1
docker commit -a $author -m $commit_message $container_id $new_image_name:$new_image_tag
  • 构建镜像
1
2
3
docker build --network=host --pull -f $docker_file -t $repo_name:$new_image_tag $context_path
# --pull:尝试去更新镜像的新版本
# context_path:上下文路径,指定构建镜像的上下文的路径,构建镜像的过程中,仅可引用上下文路径的文件
  • 删除镜像
1
docker rmi $image_id
  • 进入容器

    1
    docker exec -it $container_id bash
  • 退出容器但不关闭

    1
    Ctrl + Q + P
  • 停止/杀死容器

1
2
3
docker stop/kill $container_id
# stop:先发送 SIGTERM 信号,在一段时间之后(10s)再发送 SIGKILL 信号,使程序优雅退出
# kill:直接发送 SIGKILL 信号杀死程序
  • 删除容器
1
docker rm $container_id
  • 清理
1
2
3
docker kill $(docker ps -aq) # 杀死所有容器
docker rm $(docker ps -aq) # 删除所有容器
docker rmi $(docker images -aq) # 删除所有镜像
  • 保存与加载镜像
1
2
3
docker save $image_id > xxx.tar
docker load < xxx.tar
docker tag $image_id yyy:zzz
  • 拷贝
1
2
docker cp $container_id:$filename $target_filename
docker cp $target_filename $container_id:$filename
  • 容器内使用 GDB
1
docker run --cap-add sys_ptrace --security-opt seccomp=unconfined

上述两个选项的作用分别是:

  1. 由于 GDB 调试需要的 SYS_PTRACE 属性被禁止掉了,所以在启动容器时候需要增加这个属性
  2. GDB 调试时,需要关闭 Linux 虚拟地址随机化(虚拟地址随机化是为了安全考虑而出现的,GDB 调试只是暂时关闭)
  • 提交新的镜像
1
docker commit -m="$commit_log" $container_id $image_name:image_tag
  • 基于基础镜像构建新的镜像
1
docker build -t $image_name:image_tag .

K8s

  • 快速搭建单机环境
1
2
3
4
5
6
7
8
9
10
# 安装 minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && sudo install minikube-linux-amd64 /usr/local/bin/minikube
# 安装配套工具
yum install -y kubectl conntrack-tools
# 启动 minikube
minikube start --registry-mirror=https://dockerhub.woa.com --addons=dashboard --vm-driver=none --network=host
# 启动 minikube dashboard
minikube dashboard
# k8s 监听所有地址
kubectl proxy --address=0.0.0.0 --accept-hosts='.*'
  • 通过配置文件创建
1
2
3
4
5
6
7
8
# 增
kubectl create -f ${config_file_path}
# 删
kubectl delete -f ${config_file_path}
# 改
kubectl apply -f ${config_file_path} [--force]
# 查
kubectl get -f ${config_file_path}
  • 查询所有命名空间
1
kubectl get namespaces
  • 查询所有 pod
1
kubectl get pods --all-namespaces
  • 查询某个命名空间下面所有 pod
1
kubectl -n ${namespace} get pod
  • 查询某个命名空间下面某个 pod 的属性
1
kubectl -n ${namespace} describe pod ${pod_name}
  • 查询某个命名空间下面某个 pod 的日志
1
kubectl logs -n ${namespace} ${pod_name}
  • 拷贝
1
kubectl cp -n ${namespace} ${pod_name}:path/to/file /local/file/path
  • 进入某个容器
1
kubectl exec -it -n ${namespace} ${pod_name} bash

ssh 免密登录

  • 本机
1
2
(ssh-keygen -t rsa)
scp ~/.ssh/id_rsa.pub $user_name@$remote_ip:~/id_rsa.pub
  • 远端
1
2
3
cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

常见问题:

  1. 检查远端用户 .ssh 文件夹及其上级文件夹有无组写权限,有的话需要将其去除
  2. 更改文件夹标签:restorecon -r -vv ~/.ssh

给命令设置超时

1
2
3
4
# linux
timeout 10 ls
# macOS
gtimeout 10 ls

注:上述时间单位为秒,macOS 需要安装 coreutils

让普通用户具有某条系统命令权限(以 mount、umount 为例)

1
2
3
# /etc/sudoers
Cmnd_Alias MOUNT = /bin/mount, /bin/umount
ALL ALL=NOPASSWD: MOUNT

进程绑核

  • 启动时绑核
1
taskset -c 1,2 ./binary
  • 运行中绑核
1
2
taskset -pc 1,2 `pidof <binary>`
taskset -pc 1-4 `pidof <binary>`
  • 查看进程绑核情况
1
taskset -p `pidof <binary>`
  • 子进程会继承父进程的绑核信息,分配到 cpu0 和 cpu1 上运行的进程产生的子进程也会被分配到 cpu0 和 cpu1
  • taskset 可以用 C 函数 sched_setaffinity 和 sched_getaffinity 代替

root 用户修改文件提示 Operation not permitted

1
2
3
4
5
6
7
8
# 查看文件属性,如果有 i 标志位则表示不可修改位(immutable)
lsattr <filename>

# 去掉不可修改属性
chattr -i <filename>

# 还原不可修改属性
chattr +i <filename>

文件权限继承

1
setfacl -R -d -m user::rwx floder

shell 脚本命令行参数

1
2
3
4
5
6
7
8
9
10
11
12
while getopts a:b:c:d: option
do
case $option in
a) arg_a=$OPTARG;;
b) arg_b=$OPTARG;;
c) arg_c=$OPTARG;;
d) arg_d=$OPTARG;;
?) exit 1;;
esac
echo $option'='$OPTARG
done
shift $(($OPTIND - 1))
1
./build.sh -a 123 -b 456

监控进程内存信息

  • 保存到文件
1
vim res.sh
1
2
3
4
5
6
7
#!/bin/bash

while :
do
cat /proc/$1/status | grep VmRSS | awk '{{ print $2 }}'
sleep 1
done
1
2
3
nohup sh res.sh `pidof $binary_name` &
tail -f nohup.out
fg # 将后台运行的或挂起的任务切换到前台运行。
  • 直接监控
1
watch -n 1 echo $(cat /proc/$(pidof $binary_name)/status | grep VmRSS | awk '{{ print $2 }}')

ADB

  • 查看设备列表
1
adb devices
  • 执行 shell 命令
1
adb shell "ls -l"
  • 拷贝文件
1
2
3
adb push ${pc_file_path} ${phone_file_path}

adb pull ${phone_file_path} ${pc_file_path}

Shell 常用指令 | 系统开发

http://www.zh0ngtian.tech/posts/86659c22.html

作者

zhongtian

发布于

2020-03-06

更新于

2023-12-16

许可协议

评论