Linux Tips

录一些常用的命令行工具,方便随时取用。

包管理

Ubuntu/Debian 上查看一个包的安装了哪些文件,安装到哪里了:

  1. 先用 dpkg -l | grep vim 找到要查看的包的完整包名;
  2. 再通过包名查看安装的文件: dpkg -L neovim

小技巧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 更好的 export 环境变量的方法,避免将敏感信息暴露在命令行历史记录中
export XXX_KEY=$(cat)

# macOS 访问剪贴板,将文本写入剪贴板
echo hello | pbcopy

# macOS 读取剪贴板
pbpaste

# 生成一个 32 字节的 url safe 的 secret key
python3 -c 'import secrets; print(secrets.token_urlsafe(32))'

# 生成一个 32 字节的 hex secret key
python3 -c 'import secrets; print(secrets.token_hex(32))'

Filesystem

losetup

1
2
3
4
5
6
7
8
# bind the file test.img to loop device /dev/loop0
losetup /dev/loop0 test.img

mkfs.ext4 /dev/loop0
mount -o discard /dev/loop0 /mnt

# list all loop devices
losetup -la

Network

Network Tools 网络工具箱

fd

1
2
3
4
# 查找多种扩展名
fd '.(java|kt)'

fd '.(java|kt)' | xargs rg -U '\bLiveStream\s*\(' -l

rg

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

# -l,仅打印匹配的文件名,忽略匹配到的内容
rg -l LiveStream

# -v,反向匹配(过滤掉匹配到的)
rg -l LiveStream | rg -v getLiveStream

# '\b', 匹配 word 边界
rg -l '\bLiveStream\('

# '\s', 匹配空白字符
rg '\bLiveStream\s*\('

# -U, 匹配多行文本
rg -U '\bLiveStream\s*\('

xargs

xargs on Mac OS:

1
2
find . -iname something | xargs -I {} mv {} /dest/path
find /tmp/ -ctime -1 -name "x*" | xargs -I '{}' mv '{}' ~/play/

Crontab

1
2
3
4
5
# 每 10 分钟运行一次
*/10 * * * * command

# 开机自启动:每次系统重启时,都会运行 ss.sh
@reboot ss.sh

参考:https://crontab.guru/every-10-minutes

二进制工具

二进制 dump 工具

  • xxd 以十六进制形式 dump 文件内容
  • xxd -b 以二进制形式 dump 文件内容
  • xxd -r 从 dump 内容还原出原始文件,例如 xxd file | xxd -rcat file 的输出是一致的

查找二进制文件中的字符串(find printable strings),例如:

1
2
# 查看 /bin 目录下的程序可能会创建哪些临时文件
strings /bin/* | grep tmp

代理相关

如果你的 http_proxy 需要登录,可以设置如下:

export http_proxy=http://username:password@host:port

过滤、报告相同行

  • uniq

    相同行仅打印一次

  • uniq -c 行首插入该行重复出现的次数

  • uniq -d 仅输出相同行

  • uniq -u 仅输出不同行

系统管理相关

用户管理

usermod -a -G sudo user1 将 user1 增加到 sudo 组

su - user

当你使用带有破折号的 su - user1 命令时,系统会执行以下操作:

  1. 切换到 user1 账户。
  2. 重新初始化环境变量,包括 PATHHOMESHELL 等,使其与 user1 的默认设置一致。这些设置通常在 /etc/passwd 文件和 user1 的配置文件(如 .bashrc.bash_profile 等)中定义。
  3. 将工作目录切换到 user1 的主目录。
  4. 如果定义了登录脚本(如 .bash_profile.profile),则执行这些脚本。

使用不带破折号的 su user1 命令时,只会切换到 user1 账户,但不会重置环境变量或更改工作目录。这意味着,即使你已经切换到了另一个用户,当前环境仍然保留了原始用户的设置。

总之,使用带有破折号的 su - user1 命令可以更好地模拟一个完整的登录环境,而不仅仅是切换用户。在需要以另一个用户的完整环境执行任务时,建议使用带破折号的 su - 命令。

script /dev/null 该命令可以解决 su 切换用户后,运行 screen 程序时报错:

1
Cannot open your terminal '/dev/pts/0' - please check.

的问题。

原理是 script 命令会开启一个新的伪终端(pseudo-terminal),用来 dump 终端上的所有输出。

1
2
3
4
5
# 查看 CPU 总核心数
grep -c 'model name' /proc/cpuinfo

# 查看、配置资源限制
ulimit -a

测试硬盘速度

1
2
3
4
5
# bs 默认为 512 字节,单位支持 k/m (macOS 平台如此,Linux 上不一样)
# write
dd of=${path_on_disk} if=/dev/zero bs=1m count=1000
# read
dd if=${path_on_disk} of=/dev/null bs=1m

监控磁盘 IO 情况

1
iostat
1
2
3
              disk0               disk2               disk3       cpu    load average
    KB/t  tps  MB/s     KB/t  tps  MB/s     KB/t  tps  MB/s  us sy id   1m   5m   15m
   26.18   95  2.42    25.87    0  0.00   287.74    0  0.00   4  2 94  1.95 1.64 1.56

文件权限

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 更改文件属组
chgrp [-R] group filename

# 更改文件属主
chown [-R] owner filename
chown [-R] owner:group filename

# 更改文件属性
chmod u=rwx,g=rx,o=r  test1
chmod a-x test1

SUID, SGID, sticky bit

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 为程序设置 SGID, 程序将以文件所属组的权限运行
chmod g+s executable

# 为程序设置 SUID, 程序将以文件属主的权限运行
chmod u+s executable

# 为目录设置 SGID, 该目录下新建的文件或目录的组将默认为该目录的组
chmod g+s directory

# 设置 sticky bit, 该目录下新建的文件或目录不能被非owner删除(该目录的属主是个例外,可以删除任意文件)
chmod +t directory

SUID/SGID 提权

SUID (Set UID)是Linux中的一种特殊权限,其功能为用户运行某个程序时,如果该程序有SUID权限,那么程序运行为进程时,进程的属主不是发起者,而是程序文件所属的属主。但是SUID权限的设置只针对二进制可执行文件,对于非可执行文件设置SUID没有任何意义.

在执行过程中,调用者会暂时获得该文件的所有者权限,且该权限只在程序执行的过程中有效. 通俗的来讲,假设我们现在有一个可执行文件ls,其属主为root,当我们通过非root用户登录时,如果ls设置了SUID权限,我们可在非root用户下运行该二进制可执行文件,在执行文件时,该进程的权限将为root权限.

1
2
3
4
5
# 设置SUID位
chmod u+s filename   

# 去掉SUID设置
chmod u-s filename   

以下命令可以找到正在系统上运行的所有SUID可执行文件。准确的说,这个命令将从/目录中查找具有SUID权限位且属主为root的文件并输出它们,然后将所有错误重定向到/dev/null,从而仅列出该用户具有访问权限的那些二进制文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 列出所有 SUID 文件
find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;

# 列出所有 SGID 文件
find / -type f -perm -04000 -ls

# 列出所有全局可写文件
find / -perm -2 -type f -print

文件时间戳

  • atime

    • Access Time

    • 出于性能考虑,一般 mount 的时候会增加如下选项,导致 atime 表现和预期不一致:

      -   ``noatime`` Do not update the file access time when reading from a file          
      -   ``relatime``  Update inode access times relative to  modify  or  change  time. Access time is only updated if the previous access time was earlier than the current modify or change time.      
      
    • ls -lu 列出 atime, ls -ltu 按 atime 排序(最近的排最上面)

  • mtime

    • Modify Time,最后一次修改文件(内容)或者目录(内容)的时间
    • ls -l ls -lt 默认使用 mtime
    • cp 文件默认会改变 mtime + ctime
    • cp -a 只会改变 ctime,mtime 不变
  • ctime

    • Change Time,最后一次改变文件(属性或权限)或者目录(属性或权限)的时间
    • ls -lc ls -ltc 使用 ctime
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
stat filename

# sort by mtime
ls -lt

# sort by ctime
ls -ltc

ls -alR > /path/to/timestamp_modification.txt
ls -alRc > /path/to/timestamp_creation.txt

文件打洞

如何在一个大文件(例如 >500G)的开头,高效的插入一些内容?

如果是 Linuxe + ext4/XFS,可以考虑用 fallocate 函数,FALLOC_FL_INSERT_RANGE 标记位。

参考:https://stackoverflow.com/questions/37882286/prepend-to-very-large-file-in-fixed-time-or-very-fast/37884191#37884191

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 子目录按占用空间大小排序
du -d 1 |sort -n

# 查看 CPU 总核心数
grep -c 'model name' /proc/cpuinfo

# 在 /bin 或者 /usr/sbin 中运行,搜索哪些程序会创建临时文件
strings * | grep tmp

# 查看资源限制的设置
ulimit -a

# 测试硬盘速度
# bs 默认为 512 字节,单位支持 k/m (macOS 上,Linux 不一样)
dd of=/Volumes/disk-1t/1.out if=/dev/zero bs=1m count=10000
dd if=/Volumes/disk-1t/1.out of=/dev/null bs=1m

# 监控磁盘 io 情况,-p 指定 某个(或某些)磁盘
iostat -x 1

# 显示当前时间配置信息
timedatectl show
# 将本地时间同步到 rtc 时钟,解决 Windows 10 的系统时间不对的问题(会修改配置文件/etc/adjtime)
timedatectl set-local-rtc 1

# lazy umount
umount -l

# 下载脚本并立即执行
curl --compressed -o- -L https://yarnpkg.com/install.sh | bash

# 文件恢复到某个 revision
git checkout c5f567 -- file1/to/restore file2/to/restore

# 文件恢复到某个 revision 之前的 1 个版本
git checkout c5f567~1 -- file1/to/restore file2/to/restore

pgrep process-name
pkill process-name

loopback device

loopback device 可以将文件作为设备来挂载,类似于虚拟机的镜像文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 创建一个稀疏文件(sparse file)
dd if=/dev/zero of=1.img bs=1 count=0 seek=512M

# 将 1.img 自动绑定到一个可用的 loop device
# -P, --partscan:扫描分区
sudo losetup -fP 1.img

# 列出当前的 loop devices
losetup

# 分区
sudo fdisk /dev/loop13
# 分区之后可以看到分区的设备号,例如这里为 /dev/loop13p1

# 将分区格式化为 ext4 文件系统
sudo mkfs.ext4 /dev/loop13p1

# 挂载 loop device
sudo mount /dev/loop13p1 /mount/point

# 删除 loopback device
sudo umount /mount/point
sudo losetup -d /dev/loop13p

稀疏文件(sparse file) 的特点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ dd if=/dev/zero of=sparse_file bs=1 count=0 seek=512M
0+0 records in
0+0 records out
0 bytes copied, 0.000138743 s, 0.0 kB/s

$ ls -lh sparse_file 
-rw-rw-r-- 1 user user 512M 2月   2 22:36 sparse_file

$ du -sh sparse_file 
0       sparse_file

# -s:查看实际分配的尺寸
$ ls -lhs sparse_file
0 -rw-r--r-- 1 user user 512M 2月   2 22:36 sparse_file

如果将 sparse file 作为镜像文件挂载,会随着在设备中文件的写入,镜像文件的尺寸才会逐渐增大。

常用 Console 快捷键

快捷键动作
ctrl+l清屏
ctrl+d退出shell
ctrl+u清除光标之前
ctrl+k清除光标之后
ctrl+w清除光标之前的一个单词
ctrl+y粘贴刚才ctrl+u/k/w的内容
ctrl+t交换最后两个字符
esc+k交换最后两个单词
alt+f/ctrl+b向前/后移动一个单词
ctrl+f/ctrl+b向前/后移动一个字符
alt+d/ctrl+d删除光标后的一个单词/字符
ctrl-n/ctrl-p上一个/下一个命令
ctrl-/undo
ctrl-rreverse-i-search
!history substitution
!nRefer to command line n.
!-nRefer to the current command line minus n.
!!Refer to the previous command. This is a synonym for `!-1'.
updatedupdated2023-05-092023-05-09