个人命令行工具小结

本文总结了命令行工具如Bash和Zsh的基础操作,包括重定向、模板处理、进程管理、文件查询、编码转换,以及如何利用awk、sed、xargs等进行数据处理。此外,还介绍了如何利用Tmux进行会话管理、使用cheatsheets查阅手册和处理并行任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结并积累个人的命令行工具的经验,关注BashZsh和各类工具简单的使用。

相关参考https://github.com/jlevy/the-art-of-command-lineBash(1)

Table of Content

Bash 基础

TODO completion

重定向方式

redirection、duplication、here document、 here string、precess substitution 以及指定descriptor打开文件

Here Document 和 Here String

对于输入重定向,here document和here string允许替代文件作为输入来源,简单示例

# 使用CSV表格format输出
TemplateString='${Name},您好,今天是${Time},  大会员还有${Limit}天到期'

while IFS=',' read Name Time Limit; do
	eval "echo $TemplateString"
done <<hereDOC
小明,周三,100
abc,`date`,0
hereDOC
>>>
小明,您好,今天是周三, 大会员还有100天到期
abc,您好,今天是2022年 7月 2日 星期六 14时03分03秒 CST, 大会员还有0天到期

Process Substitution

process substitution 应用于接受文件作为输入的程序,其构建FIFO管道,将进程的输出与管道连接起来。

# 打印构建的管道
echo <(echo hello)
>>> /dev/fd/63

# 合并两个表格
paste <(cut -f 2 table1) table2 <(echo "gene table3")

为Shell本身打开文件

使用[fd]<>[name]的语法,打开特定文件并设置为fd

# 打开/tmp/text,并设置为fd为3
exec 3<>/tmp/text
# 查看bash打开的文件
lsof -p $$
>>>
OMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
bash    966453  zyh  cwd    DIR  253,0     4096 3410306 /home/zyh/pFedMe-master
bash    966453  zyh  rtd    DIR  253,0     4096       2 /
bash    966453  zyh  txt    REG  253,0  1183448 8651993 /usr/bin/bash
bash    966453  zyh  mem    REG  253,0    51832 8661222 /usr/lib/x86_64-linux-
bash    966453  zyh    0u   CHR  136,1      0t0       4 /dev/pts/1
bash    966453  zyh    1u   CHR  136,1      0t0       4 /dev/pts/1
bash    966453  zyh    2u   CHR  136,1      0t0       4 /dev/pts/1
bash    966453  zyh    3u   REG  253,0        0 5385085 /tmp/text
...

注意这里的execbuiltin是必须的,因为bash默认的执行模式是fork-exec,也即命令行打开的文件是子进程的,与bash本身无关。只有仅使用exec才能避免fork

另外,一般不需要为Shell主动打开文件,不过如果想保持一个PIPE存活,那么就必须使用shell打开pipe,否则进程打开的pipe会自动关闭,在进程退出时。

使用set更改bash选项

更常用于bash脚本,包括

  • -x, debuggging output
  • -u, detect unset variable usage
  • -e, abort on errors

bash脚本的特殊参数

  • positional parameters: $1, $2,…。为传入参数
  • *$*等价于$1c$2c$3...,c为IFS变量的第一个字符
  • @,与$*一致,但当"\$@" 的效果为"$1" "$2" ...。这一点在处理包含空格的参数时比较重要
  • #,positional parameters的个数
  • ?,前一个程序的执行状态
  • $,当前shell的pid,通过命令很难直接获取
  • !,上一个后台task的pid
  • 0,第一个参数,为命令名或script名

算术/逻辑运算

  • ((arithmetic exprsssion)) ,返回0,1作为判断,也有$((arithmetic expansion))版本, 等价于 letbuitin
  • [[ conditional expression ]], 注意要有空格,基本与 test,[]等价,不过常在判断中用[]

bash展开顺序

man bash EXPANSION 节 的相关笔记。可以看作readline(3)的后续。

bash 展开发生在第一次 word split之后,展开顺序的重要性在于,以下操作不能逆序发生,这对理解bash行为很有帮助

  • brace expansion
  • tilde expansion, 具有~前缀的特殊内容,例如~
  • parameter expansionr, 变量展开,最常见的,
  • arithmetic expansion,用于变量的计算
  • command substitution,较为常用
  • word splitting
  • pathname expansion,又称glob

理解这个展开特性很有用,但不能使用在这些比较角落的规则,就像尽量不要使用晦涩的操作符优先级顺序一样,强行利用bash展开顺序来写脚本的结果只能更坏。

Zsh的增强补全

kill命令需要PID才能发送信号。但在zsh下,增强的补全机制可以允许使用对comm栏进行搜索。此外,ls能够通过补全浏览所有可选项。等等,TODO。

理解unix下的inode

  • inode是文件的元信息,使用stat <file>查看的即为该部分数数据
  • unix对文件的存储分为数据区和inode区两部分,区域在硬盘初始化时变已经确定,使用df -i可以查看包括inode区的信息
  • open(2) 文件,从文件名到数据的索引流程
    • 打开目录文件,查找到文件名对应的inode号
    • 根据inode号找到文件的inode数据,进一步找到文件在数据区的位置
  • inode信息并不包括文件名,文件名在目录的索引过程被使用

理解readline(3)对于bash的作用

readline(3)是bash默认使用的读取行的API,readline(3)本身是一个很强大的库,能够提供‘编辑’能力,具体地:

设想一下,terminal如何识别用户输入的\b(删除键)并执行相应的行为,read(2)肯定做不到,你会得到"helll\bo world"的字符串,需要自己识别并做出处理。而所谓editing的功能,就是这些readline(3)会帮你完成。但readline(3)的能力不仅限于此,它应当是bash最早解释key sequence的API,提供很多基础快捷键。

因此,想增强对bash输入输出的理解

man 3 readline

很值得参考。

Embarrassing Parallel

并行的最简单形式 —— 通过直接运行多个实例。

  1. bash 的并行原语 —— &wait,编译示例:

    for file in ls *.cpp; do g++ -c $file &; done
    wait && g++ *.o 
    
  2. 利用pipe进行并行。pipe默认分别在subshell中运行程序,程序间通过管道通信,但工作方式是非同步式的,有时可以作为并行使用。

使用cheat sheets查找在线手册

cheat.sh: Unified access to the best community driven cheat sheets repositories of the world.
cheat.sh很好用,而且示例丰富,例如:

curl cheat.sh/tar
>>> 
cheat.sheets:tar 
# tar
# GNU version of the tar archiving utility

# An approach to backing up the current user's HOME, using tar(1) and Gzip
# compression. Permissions (modes) will be preserved. The filename format will
# be: UID:GID_DATE.tgz
#
# Replace 'DEVICE' with whichever device is applicable to you, but note that it
# must be in the '/media/USER' (where USER is the username) directory, else
# this won't work, unless you edit the formatting section of `printf`.
tar -czvpf "$(printf '/media/%s/%s/%d:%d_%(%F)T.tgz' "$USER" 'DEVICE' ${UID:-`id -u`} ${GID:-`id -g`} -1)" "$HOME"

# Delete file 'xdm' from the archive given to the `-f` flag. This only works on
# non-compressed archives, unfortunately, but those can always be uncompressed
# first, then altered with the `--delete` flag, after which you can recompress.
tar --delete -f xdm_edited.tar.gz xdm
...

可以作为man(1)的替代和补充

命令行工具

Tmux - Re-attachable session

Use screen or tmux to multiplex the screen, especially useful on remote ssh sessions and to detach and re-attach to a session. byobu can enhance screen or tmux by providing more information and easier management. A more minimal alternative for session persistence only is dtach.

在SSH中利用Tmux运行datachable的终端
在远程运行耗时较长的程序时最好使用这个,避免意外退出ssh导致的进程中止。也可以使用

# 在后台运行'&',并忽略control terminal结束时发送的HUP信号。即,一个dedached程序
# 当然还需要重定向输入 
nohup longrunning 2>&1 >/tmp/long.out &

当然,麻烦了许多

模板处理工具

  • here document可以嵌入简单的模版
  • envsubst(1)命令可以直接对模板文本中的shell变量进行替换(需要使用$标识)
  • python中用string format也可以支持模版

文件的通用查询工具

stat - display file status (inode)

fuser - list process IDs of all processes that have one or more files open

lsof - list open files

realpath - resolve pathname

file – determine file type

ls - list directory contents

使用fzf或percol可以交互式地过滤输出

(TODO,应用类别)

需要安装。不过有zsh、oh-my-zsh会更方便。感觉自己也比较少用了。

ubuntu下使用update-alternatives更改不同版本的软件

常见场景:

  • 更改python3对应的次版本号。
  • 更改默认使用的gcc版本。

update-alternatives包括三种主要命令:query、install、config/auto

  • update-alternatives --query <target>查询一个 <target> 的所有<alternatives>

  • --install,注册一个<alternative>,具体地

    # update-alternatives --install <path to linked target> <taegt name> <path to excutable> <priority vaule>
    sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90 --slave /usr/bin/g++ g++ /usr/bin/g++-9
    
  • --config <target>手动选择<target>的的<altenative>, --auto <target> 已经<alternative>的priority value自动选择。

改变文件的encoding

vscode可以直接操作,但是只能一个一个弄。命令行方式可以参考,主要使用命令

  • file -i确定当前encoding
  • iconv -l 列出支持的编码
  • iconv -f <encoding1> -t <encoding2> inputfile [-o file]

其他话题

  • Job Management

    &, ctrl-z, ctrl-c, jobs, fg, bg, kill, pkill/pgrep, etc.

  • filesytem management

    df, mount, fdisk, mkfs, lsblk, etc.

  • Network management

    ip or ifconfig, dig, traceroute, route, etc.

  • version control system

    init, clone, fetch, merge, pull, push etc.

  • regular expressions

    grep/egrep, -i, -o, -v, -A, -B, -C

  • package management softwares

    apt-get, yum, brew

    pip(python based tools), etc.

Other one-liners

从文件获取命令参数,按行传输给程序

  1. xargs默认使用空格和换行分割参数,并为程序传入尽可能多的参数,因此一次传入的参数量一般不为一行,需要特殊指定为每行,参考
    # 通用, 注意—I具有限制,-L每行末尾不能是空行
    cat /tmp/params_perline | xargs -I{} -L 1 my_program {}
    # GNU xargs, -d选项
    cat /tmp/params_perline | xargs -d '\n' my_program 
    
  2. read builtin,按行读取
    while read line; do my_program $line; done < /tmp/params_perline
    
    需要注意行中的空格的影响,更直接的,可以使用
    while read line; do eval "my_program $line"; done < /tmp/prarms_perline
    

xargs并行处理参数

xargs中的命令不能传入&,但具有并行执行的参数

cat params | xargs -I{} -P 0  ./myprogram {}

简单制表

xargs能够使用-n限制传入参数,再将分隔符换为\t即可完成简单制表。

head -n 100 /usr/share/dict/web2 | xargs -n 5 | tr ' ' '\t' 

但这样会出现类似

DB	Size_in_MB
foobar	11011.2
barfoo	4582.9
donkey	4220.8
shoryuken	555.9
hadouken	220.0
kong	214.8
super_mario_bros_p	211.1

的词长不匹配。使用column -t能将这样长度不匹配的表格进行对其,

head -n 100 /usr/share/dict/web2 | xargs -n 5 | column -t

查找/usr/lib下占内存最大的20个文件

因为du不区分文件和目录,需要使用find区分;使用sort -h排序具有单位的数据。

find /usr/lib -type f | xargs du -h | sort -rhk 1

以树状打印进程,可视化程序间关系

pstree(1) – list processes as a tree

# 打印 NetworkManager 及其子进程
pstree -p `pgrep NetworkManager`

使用lsof(8)列出正在使用tcp监听网络接口的相关程序

sudo lsof -iTCP -sTCP:LISTEN -P -n
>>>
COMMAND       PID            USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
systemd-r    2194 systemd-resolve   13u  IPv4   102699      0t0  TCP 127.0.0.53:53 (LISTEN)
cupsd      618782            root    6u  IPv6 51371751      0t0  TCP [::1]:631 (LISTEN)
cupsd      618782            root    7u  IPv4 51371752      0t0  TCP 127.0.0.1:631 (LISTEN)
...

构造一个detached process

在远程运行耗时较长的程序时需要避免意外退出ssh导致的进程中止,需要做的工作有:

  1. 程序置于后台(不占用terminal)
  2. 将程序从control terminal脱离(nohup)
  3. 将输入输出与control terminal去关联(否则可能会在输出时失败)

具体的解释仍有待完善(TODO:进程间的组织形式,group、session;特殊进程deamon的构造方法),但简单使用仅需要nohup即可。

# nohup 将到terminal的标准输出和标准错误重定向到./nohup.out,忽略SIGHUP,使用&置于后台。
nohup <utility> [arguments] &

快速建立一个http server

# 在当前目录建立http server,并在9000端口侦听
python -m http.server 9000

快速建立一个TCP Server

# 监听9000端口
nc -kl 9000

bash 快速连接并发送一份tcp数据

# 与127.0.0.1:9000上的tcp server握手,并发送数据 "hello world\n"
echo hello world > /dev/tcp/127.0.0.1/9000

使用mktemp构建临时文件

文件一般在/tmp/var/tmp,会自动每隔10/30天自动清理

使用seq 命令生成比{start...end}更复杂的序列

TTY源于TeleTYpewriter

使用RE处理跨行文本

sed和awk默认只能单行处理,perl可以使用-0777来将整个文档视为单行处理,而-p可以模拟sed

TODO:AWK应该也行

# 删除文本的空行
perl -0777 -pe 's/\n+/\n/g' file1

kill某一进程组

(TODO待完善)

对于多个关联的进程,例如jobs或由某一程序发起的一系列进程,例如

# 在命令行关闭vscode
kill `ps -o pgid,comm -A | grep "Visual Studio Code" | cut -d ' ' -f 1  | sort -rn | uniq`

关键是需要确定进程所属的进程组pspgid项便是所属进程组,而sortuniq清除冗余,再使用kill即可。

命令行与剪贴板交互

pbcopy, pbpaste - provide copying and pasting to the pasteboard (the Clipboard) from command line

# 拷贝“hello world\n”到剪贴版
echo hello world | pbcopy

AWK重命名列表序号,并拷贝到剪贴板

# 序号类型为 /[0-9][0-9]?\./
awk '
	BEGIN {COUNT=1} 
	{ COUNT+=sub("[0-9][0-9]?\\.", sprintf("%d.", COUNT)); 
		print}
' tables.txt | pbcopy

查询utf-8编码的文件里的unicode字符

对应uniutils中的uniname

# 仅接受文件作为输入,简单使用为
uniname <(echo -e "\xF0\x9D\x9C\x82") # utf-8编码下的eta
---
character  byte       UTF-32   encoded as     glyph   name
        0          0  01D702   F0 9D 9C 82    𝜂      MATHEMATICAL ITALIC SMALL ETA
        1          4  00000A   0A                     LINE FEED (LF)

目前根据unicode name查找codepoint的工具,在vscode插件中能找到,命令行中还不太行。python的unicodedata包只有完全匹配的方法。

Processing files and data & System debugging(TODO)

https://github.com/jlevy/the-art-of-command-line

取消bash history的数目限制

bash(1)Shell Variables的两个参数:

  • HISTFILESIZE - The maximum number of lines contained in the history file.
  • HISTSIZE - The number of commands to remember in the command history.
    其中负数为不设限。因此将
export HISTSIZE=-1
export HISTFILESIZE=-1

加入.bashrc即可。如果仍有问题(不知道怎么就发生了 truncation),参考how-to-unlimited-bash-shell-history

Anaconda 更改python版本

# 3.10
conda install python=3.10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值