Linux命令拾遗-入门篇
原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。
简介
之前出过很多和Linux命令有关的文章,但都比较零散,故打算出一个Linux系列文章,一步一步带出Linux中纷繁复杂的命令知识。
本篇是第一章,主要讲解Linux命令基本使用,并带认识一些最基础的Linux命令使用。
基础知识
当我们打开终端时,终端软件会为我们打开一个shell软件,这个shell会显示一个提示符,然后等待用户输入命令,类似下面这个:
然后我们就可以在这个界面中执行Linux命令了,shell做为一个命令解释器,它会解释并执行用户输入的命令。
这种shell有多种,如sh、csh、tcsh、zsh、fish、bash,而目前Linux环境中使用得最广泛的就是bash。
命令参数与选项
Linux命令基本都是如下的形式:
cat -n temp.txt
这个命令表示输出temp.txt的内容,同时包含行号,其中,cat是命令程序,-n是选项,而temp.txt则是命令参数。
一般来说,选项用来控制命令的行为,参数用来给命令输入数据。
标准输入、标准输出、标准错误
命令除了参数与选项外,还有标准输入、标准输出与标准错误这3个概念,如下:
标准输入
同样是用来给命令输入数据,它与命令参数的区别是,参数一般是一个(或多个)简短的文本值,而标准输入是一个输入流,命令可从其中读取大量数据,类似java的System.in
。
cat < temp.txt
它等效于cat temp.txt
,但本质却是不同的,cat temp.txt
是cat这个程序内部会去读取temp.txt文件的内容,cat是知道它在读取temp.txt的,而cat < temp.txt
是cat这个程序在读取标准输入中的数据,至于标准输入中的数据从何而来,cat是不知道的。
同时,Linux命令中也经常使用 -
这个特殊的文件名来表示标准输入文件,如下四个命令是等效的:
# cat不指定输入文件时,默认就读取标准输入
cat
# cat认为 - 代表标准输入文件
cat -
# /dev/stdin是具体的标准输入文件
cat /dev/stdin
# 指定读取0(标准输入)这个文件描述符
cat <&0
标准输出
每个命令都有一个标准输出,这个类似标准输入,也是一个流,不过它是用来给命令向外部输出数据的,默认是屏幕,它类似java的System.out
。如下:
# 命令默认写出内容到标准输出
echo hello | cat
# 显示指定写到标准输出文件
echo hello | cat > /dev/stdout
另外,在有些命令中,也会使用-
来代表标准输出文件。
标准错误
标准错误概念上和标准输出类似,不过它是用来程序报告错误的,类似java的System.err
。如下:
# 显示指定写到标准错误文件
echo hello | cat > /dev/stderr
管道
管道的作用是把命令之间连接起来,让它们之间可以传递数据,上面其实已经见过管道,如下:
echo hello | cat
echo程序将hello写到标准输出,| 将echo的标准输出与cat的标准输入连接起来,前面标准输出写出什么数据,| 就会将这个数据传到后面程序的标准输入,行为就像管道一样。
默认情况下,管道只能将前面的标准输出传递给后面的程序,如果想将标准错误也传递给后面程序,可以使用|&
# 标准输出与标准错误都通过管道传递给cat
echo hello |& cat
# 与上面等价
echo hello 2>&1 | cat
重定向
<
输入重定向,将文件内容重定向为程序的标准输入
cat < temp.txt
<<
也是输入重定向,可即时输入多行文本,bash的Here Document语法
cat <<EOF
hello,java
hello,bash
EOF
<<<
也是输入重定向,可即时输入一行文本,bash的Here String语法
cat <<<hello
>
标准输出内容重定向到文件,覆盖写入
echo hello | cat > temp.txt
>>
标准输出内容重定向到文件,追加写入
echo hello | cat >> temp.txt
>&2
标准输出内容重定向到标准错误
echo hello >&2
# 其实也可以写成这样
echo hello 1>&2
2>&1
标准错误重定向到标准输出
# 标准输出与标准错误都重定向到app.log,注意2>&1要放在后面
echo hello | cat > app.log 2>&1
# 简写形式,与上面等价
echo hello | cat &> app.log
管道与重定向揭秘
程序中使用文件描述符来引用一个文件,类似java中的File对象,但它是一个数字,又有点像指针,这个指针指向具体的文件。
而linux中,0就是标准输入的文件描述符,1就是标准输出的文件描述符,2就是标准错误的文件描述符
重定向本质是改变文件描述符的指向,如下:
1、执行cat命令后,在另一个shell中查看此cat的文件描述符,发现1标准输出指向/dev/pts/1
。
2、结束cat,我们再执行cat > temp.txt
,在另一个shell中查看此cat的文件描述符,发现1标准输出这个文件描述符指向了/tmp/temp.txt
,所以,懂了么~
管道本质是创建一个临时管道文件,将前面程序的1标准输出指向这个临时文件,后面程序的0标准输入也指向这个临时文件,如下:
1、执行cat|cat
命令
2、不要退出,在另一个shell中查看这两个cat的文件描述符,如下:
注:shell会默认为管道符 | 创建临时管道文件,如果有需要你也可以通过mkfifo显示创建管道文件。
注:只执行一个cat后,命令在等待输入流的数据,所以看起来卡住了,这时可以使用Ctrl + d
来退出,这和Ctrl + c
是不同的,Ctrl + d
作用类似于EOF信号,而Ctrl + c
是中断了进程。
Linux命令分类
基础命令
(cd ls cp mv rm pwd du df tree find locate touch stat basename dirname realpath tar)
(echo printf seq yes tee date time dos2unix iconv bc sleep watch true)
文本命令
(find xargs grep sed awk jq cat head tail wc sort uniq comm join paste cut tr)
进程管理
(ps pstree kill pidof pgrep pkill nohup jobs bg fg disown fuser)
信息收集类
(lsof /proc netstat)
系统信息类
(lscpu lsblk lsscsi fdisk hostname uname dmesg ifconfig ethtool)
资源监控类
(top free vmstat iostat sar iftop dstat nmon glances bpytop)
诊断类
(strace tcpdump gdb gprof pmap pstack gcore perf systemtap bcc bpftrace)
网络工具类
(ncat socat ping telnet host nslookup traceroute mtr ngrep tshark tcpdump nmap whois)
注:网络类命令在这篇文章里面有过系统介绍,感兴趣可前往查看常用网络命令总结
开发辅助类
(curl wget mysql screen tmux ssh scp sshpass expect nano vim emacs)
用户管理类
(su sudo w who whoami id)
常用基础命令
输出
# 输出hello,并且尾部输出一个换行符
$ echo hello
hello
# 输出hello,尾部无换行符
$ echo -n hello
# -e使用echo可以解释\n\t这样的转义符
$ echo -e 'a\nb\tc'
a
b c
# 效果类似-e,不过用的是bash的语法特性
$ echo $'a\nb\tc'
a
b c
# 格式化输出,类似C语言的printf函数
$ printf "id:%d,name:%s\n" 1001 zhangsan
id:1001,name:zhangsan
# 参数多于占位符时,printf会重复
$ printf "id:%d,name:%s\n" 1001 zhangsan 1002 lisi 1003 wangwu
id:1001,name:zhangsan
id:1002,name:lisi
id:1003,name:wangwu
目录操作
# 切换到/home目录
$ cd /home
# 切换到当前用户家目录
$ cd
# ~也代表家目录
$ cd ~
# 切换到上次的目录
$ cd -
# 显示当前目录
$ pwd
# 列出目录下的文件或目录
$ ls
# 列出当前目录与一层子目录,用了shell的*号扩展功能
$ ls *
# 列出文件或目录,并显示详细信息,ll命令与其等价
$ ls -l
# 列出文件或目录,时间倒序
$ ls -lt
# 列出文件或目录,大小倒序
$ ls -lS
# 树形显示目录与子目录中的文件
$ tree
# 只显示2层目录结构,-L 2表示递归深度为2
$ tree -L 2
# 显示目录以及子目录的大小
$ du -h
# 显示当前目录的大小
$ du -h -s
# -d1表示递归深度为1,即显示当前目录下的目录或文件大小
$ du -h -a -d1
# 当前目录下,创建temp目录
$ mkdir temp
# 创建多级目录
$ mkdir -p temp/test/work
# 当前目录下,删除temp目录,需保证待删目录是空的
$ rmdir temp
# 重命名目录,也可以重命名文件
$ mv temp temp_bak
# 移动目录,也可以移动文件
$ mv temp /tmp/temp_bak
文件操作
# 创建文件,touch实际是用来更新文件访问时间的,不过如果文件不存在会默认创建它
$ touch temp.txt
# 写入hello,会覆盖原来内容
$ echo hello > temp.txt
# 追加写入hello
$ echo hello >> temp.txt
# 查看文件内容
$ cat temp.txt
# 清空文件内容
$ echo -n > temp.txt
# 复制文件
$ cp temp.txt temp_bak.txt
# 删除文件
$ rm temp_bak.txt
# 查看文件类型
$ file temp.txt
temp.txt: ASCII text
# 查看文件属性,大小/日期等
$ stat temp.txt
File: temp.txt
Size: 6 Blocks: 8 IO Block: 4096 regular file
Device: 810h/2064d Inode: 186702 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ work) Gid: ( 1000/ work)
Access: 2021-10-10 15:24:11.256764900 +0800
Modify: 2021-10-10 15:24:09.326764900 +0800
Change: 2021-10-10 15:24:09.326764900 +0800
Birth: -
# 只获取文件大小
$ stat -c %s temp.txt
6
# 获取路径上最后一级目录或文件名
$ basename demo/temp.txt
temp.txt
# 获取目录名
$ dirname demo/temp.txt
demo
# 获取全路径名称
$ realpath demo/temp.txt
/home/work/demo/temp.txt
# 获取软链接指向的文件
$ readlink /bin
usr/bin
# 修改文件所有者与读写权限
$ chown -R work:work test/
$ chmod -R 775 test/
# 查看文件系统空间使用情况
$ df -h
#将本地/home/work/目录下的文件上传到远程/home/work/目录里
$ scp -r /home/work/* work@10.76.2.83:/home/work/
#将远程/home/work/目录下的文件下载到本地/home/work/目录里
$ scp -r work@10.76.2.83:/home/work/* /home/work/
文件打包与压缩
#压缩文件为*.tar.gz(f必须在最后面)
$ tar -cvzf files.tar.gz files/
#这两个命令与上面等价
$ tar -cvf files.tar files/
$ gzip files.tar
#查看压缩文件
$ tar -tvzf files.tar.gz
#解压tar.gz文件到/opt/目录
$ tar -xvzf file.tar.gz -C /opt/
#解压zip、Jar文件
$ unzip arthas-bin.zip -d arthas-bin/
$ unzip -O cp936 file.zip
#解压rar文件
$ rar x file.rar
进程管理
# 列出所有进程,BSD格式
$ ps aux
# 列出所有进程,Linux格式
$ ps -ef
# 列出java进程
$ ps -fC java
# 查看进程号为523的进程
$ ps -fp 523
# 查看进程树
$ pstree -Tp
# 查看当前shell的进程树,其中$$会被shell解释为当前shell的进程号
$ pstree -Tp -s $$
init(1)───init(104)───init(105)───wsltermd(106)───bash(107)───bash(121)───pstree(7203)
# 杀死523号进程
$ kill 523
# 强制杀死523号进程,如果你确定强杀也没关系的话
$ kill -9 523
# 列出所有java进程的进程号,类似命令还有pidof
$ pgrep java
# 杀死所有java进程
$ pkill java
其它
# seq可以输出连续数字
$ seq 4
1
2
3
4
$ seq 3 5
3
4
5
# yes会不断输出y,本是用来自动确认交互脚本的,但其也可指定输出字串
$ yes hello | head -n4
hello
hello
hello
hello
# 显示当前时间串
$ date +'%FT%T%z'
2021-10-10T16:31:50+0800
# 显示当前时间缀
$ date +%s
1633854633
# 时间串与时间缀互转
$ date -d '2021-10-10T16:31:50+0800' +%s
1633854710
$ date -d '@1633854710' +'%FT%T%z'
2021-10-10T16:31:50+0800
# time用来测量命令执行时间,sleep用来睡眠指定时间,默认秒
$ time sleep 5
real 0m5.010s
user 0m0.001s
sys 0m0.000s
# tee用于同时写数据到文件和标准输出
$ seq 5 | tee temp.txt
1
2
3
# 同时tee也可以用于观察流过管道的数据,只需要写到/dev/tty即可,而bc是一个命令行版的科学计算器
$ seq -s+ 4 | tee /dev/tty | bc
1+2+3+4
10
# 将windows的换行符\r\n替换为\n
$ dos2unix temp.txt
# 将文件编码从GBK转到UTF-8
$ iconv -f GBK -t UTF-8 temp.txt > temp_utf8.txt
# watch用于不断观察命令输出结果,如下观察日志的写入情况
$ watch -d -n1 ls -lt logs/
# split用于文件拆分,比如按10M大小拆分日志文件,拆分后文件名类似app0001
$ split -b 10m app.log -d -a4 app
# type用于查看命令安装位置,which命令也可以,不过更推荐使用type
$ type ps
ps is hashed (/usr/bin/ps)
如何学习Linux命令
# 命令内置的help,一般记录了各命令选项的作用
$ awk --help
# man与info记录了命令的详细说明
$ man awk
$ info awk
# tldr记录了命令常见用法
$ tldr awk
# cht.sh综合了tldr与man的能力
$ curl cht.sh/awk/:learn |less -R
# coreutils软件包含有日常使用的绝大多数常用命令,值得了解下
$ info coreutils
更美观的Linux命令
如果你喜欢折腾,就把下面链接中的全部装上吧!
https://github.com/ibraheemdev/modern-unix
知识延伸指引
标准输入没有重定向时,指向 /dev/pts/1
,它是啥东西?
往期内容
长按关注【打码日记】