文章目录
参考链接
【Linux操作系统超神之路】进程的概念
command --help:可以查看该命令详情
man command:可以查看详细的命令详情
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7e157a214102a289b64345270ff90440.png)
Linux的命令都是在内存中执行的,防止cat等操作,读取超大数据量。
Linux基础知识
Linux 系统中一切皆文件。
转义字符\的作用就是将具备特殊含义的字符转义声明为普通字符使用,同理\表示将自身转义为普通反斜杠字符。
- 在Linux系统中,文件类型不是通过后缀来区别的,所以有无后缀并不重要,但是为了方便对文件进行区别识别,通常加上后缀(命名识别)。例如:.tmpl=template:模板文件
- Linux的扩展名,,Linux的文件是没有所谓的 扩展名的,就好比 test.txt 这个文件,一看就是普通文件了。其实 在linux里
.txt 也是文件名的一部分,和windows是不一样的(windows里如果你更改了文件名,就会提示你文件属性会跟着改变。
比如test.txt文件,双击打开后,默认是文本编辑器打开的,后缀改为pdf后 ,默认打开方式就变成了pdf编辑器) - 一个Linux文件能不能被执行,与x权限有关,与文件名根本一点关系也没有。虽然扩展名不起作用但是我们还是希望可以由扩展名了解此文件是什么东西。所以,在编写linux的文件的时候,最后把后缀名带上,就类似于把文件归个类,即一看到这个文件就知道这个文件的大概用途。
简单理解:xxx文件与 xxx.txt或是 xxx.sh 是没有本质区别的
/Home:不同用户目录操作空间的主目录。
一般都是基于/home/user/下进行命令操作。
- 绝对路径的优劣:可以在任意目录下执行有关绝对路径的命令,但是可能导致命令过长。
- 相对路径的优劣:命令长度自由控制,但是需要在指定路径下执行命令。
1.绝对路径与相对路径 我们知道Linux的目录结构为树状结构,最顶级的目录为根目录 /。
其他目录通过挂载可以将它们添加到树中,通过解除挂载可以移除它们。
绝对路径: 路径的写法,由根目录 / 写起,例如: /usr/share/doc 这个目录。
相对路径: 路径的写法,不是由 / 写起,例如由 /usr/share/doc 要到 /usr/share/man 底下时,可以写成: cd ../man 这就是相对路径的写法。
只要不是从/开始的都是相对路径,默认相对位置为当前路径。
自定义命令
Linux环境可以支持软件自定义命令,例如安装的对应软件都可以在terminal通过其对应的命令触发实现操作:docker,git。
原生:shell命令->解释器->系统调用->Linux内核
软件:软件自定义命令->对应可执行文件->系统调用->Linux内核
linux自定义命令
/bin目录中包含可执行命令,可以找一下对应的软件自定义命令
或者根据PATH变量中指定的存储可执行命令的路径,一一查询对应的软件自定义命令。
which command就可以查询PATH变量全部存储路径中的可执行文件命令。
读写操作
写操作时若没有对应文件则会直接自动新建文件并写入,读操作不行若没有对应文件那就是没有,无法读取,无法解决。
实例:安装软件时都是自建软件名文件夹然后安装写入。
command -options
command的-后面可以接多个option
例如:ls -lrt,rm -rf等等
Linux之root用户,以及命令sudo与su
Sudo为临时使用Linux的root权限
注意: Linux中 管理员账户是 #, 普通账户是 $
Linux基础文件管理命令
注意
Linux命令管理文件的精髓:文件管理命令都可以批量操作文件(灵活利用通配符*)
所有文件操作命令都可以和路径结合食用。
操作内容用正则,操作文件名用通配符
例如:
rm *.txt:删除所有txt类型文件
rm dir_* -r:删除所有dir_开头的文件夹
mv *.txt dir:移动所有txt文件到dir文件夹下
ls *.sh:列出当前目录下所有sh文件
rm/cat/ls ABC*:查看/展示/删除ABC前缀的文件
cat *.sh > all.sh:将当前目录下的全部sh文件内容读取并重定向stdout输出为all.sh文件
grep xxx ./*.filetype:将path下的全部filetype文件内容进行查询匹配逐行输出=》文件名:匹配列
rm,mkdir,cp等操作文件夹要加-r
~======/home/uesr_name( 当前用户目录的绝对路径)
linux 中的“~”和“/”
- Linux所有文件命令都可以基于绝对路径和相对路径以及.和…等等
一个.表示当前目录,两个.表示上层目录
pwd命令可以显示当前工作目录的绝对路径。其中pwd是print working directory 的缩写。
Linux内核通过进程对任务进行管理,在终端界面启动一个进程后,使用Ctrl+Z和Ctrl+C都可以用退出进程,返回到终端界面。区别在于:
- Ctrl+C中断了进程,返回到终端界面。
- Ctrl+Z暂停了进程,返回到终端界面。
如果将终端比作前台,终端背后所看不到的系统比作后台,Ctrl+Z将进程暂停并挂在了后台,使用户可以继续查看和操作前台终端。
文件管理命令(图形化界面能做的Linux命令也能做到)
(1) ctrl c: 取消命令终止进程,并且换行
(2) ctrl u: 清空本行命令
(3) tab键: 可以补全命令和文件名,如果补全不了快速按两下tab键,可以显示备选选项
history:显示历史命令
(4) ls: 列出当前目录下所有文件,蓝色的是文件夹,白色的是普通文件,绿色的是可执行文件
所有被隐藏的文件都是以.开头的
ls *.filetype:列出当前目录下所有filetype类型的文件。
ls -lrt 表示 按修改时间 倒序 列出当前工作目录下的所有文件的详细信息
作用:目录新增文件时,根据时间排序快速查找对应新增文件,最底的就是新增文件。
ls -lrth 多列出了各个文件大小
ll既可以查看该目录文件还可以查看对应权限
find xxx:查看当前目录下该xxx文件的文件以及结构
(5) pwd: 显示当前绝对路径(change directary:进出某目录都只能用cd)
(6) cd XXX: 进入XXX目录下,
- 默认cd 无参数==cd ~
- cd .当前目录
- cd … 返回上层目录
- cd 绝对路径(/)可以进入任意目录
- cd 相对路径只能以当前目录为基准跳转对应目录
- cd -返回上一次待过的目录
(7) cp XXX YYY: 将XXX文件复制到YYY,XXX和YYY可以是一个路径,比如…/dir_c/a.txt,表示上层目录下的dir_c文件夹下的文件a.txt
cp=复制+粘贴+重命名
cp 文件夹A 文件夹B -r:将A文件夹复制到B文件夹中。
cp 文件夹A ./重命名a -r
mv 文件A 文件夹B:类似剪切功能
若mv 文件A 文件a:实现重命名功能
注意:
mv重命名是修改原文件。
cp=复制+粘贴+重命名,原文件不变,复制产生新命名文件。
cp,mv 支持线程处理,指令后加入参 --threads 线程数,例如 cp --threads 10 -r dir1 dir2
(8) mkdir XXX: 创建目录文件夹XXX
mkdir qlu\ gcl:文件夹名为qlu gcl
(9) rm XXX: 删除普通文件; rm XXX -r: 删除文件夹
rm * -r:删除当前目录下的所有文件夹和普通文件以及隐藏文件
rm *:删除当前目录下的所有普通文件
rm XXX -rf:强制删除XXX文件夹
(10) mv XXX YYY: 将XXX文件移动到YYY,和cp命令一样,XXX和YYY可以是一个路径;重命名也是用这个命令
(11) touch XXX: 创建一个文件
(12) cat XXX: 展示文件XXX中的内容
(13) 复制文本
windows/Linux下:Ctrl + insert,Mac下:command + c
(14) 粘贴文本
windows/Linux下:Shift + insert,Mac下:command + v
(15) tree查看当前目录文件的树形结构
Linux的tmux(Terminal MultipleXer)笔记
同理:
此处的命令是将ls -lrt挂载到服务执行并将执行结果重定向输出到test.txt文件中
将command命令挂载到服务器端执行,并且在默认情况下(非重定向时:无>),会将命令运行结果输出一个名叫 nohup.out 的后台进程运行日志文件到当前目录下。
一般情况下配合tail食用,follow跟踪观察挂载到服务器命令执行结果。
tail -f nohup.out
ctr + c终止跟踪,退出界面。
或者
ps -ef | grep command
功能:
(1) 同一窗口分屏。
(2) 允许断开Terminal连接后,继续运行进程。(将任务挂到云端服务器执行不受终端的开关影响)
当突然断电断网的时候tmux任务不受终端影响。
tmux a(attach):进入上次tmux窗口继续运行命令。
结构:
session:登录操作服务器的会话
window:terminal窗口
pane:teiminal窗口的分割单位
shell:命令交互程序
一个tmux可以包含多个session,一个session可以包含多个window,一个window可以包含多个pane。
实例:
tmux:
session 0:
window 0:
pane 0
pane 1
pane 2
...
window 1
window 2
...
session 1
session 2
...
Ctr+a s
查看tmux构建的全部session
筛选进入想进入的session
查看所有tmux打开的session
tmux ls
清空所有tmux构建的session
tmux kill-server
清除指定的tmux构建的session
tmux kill-window -t session序号
操作:
- 以下ctr+*操作命令:仅在tmux构建的window下有用
- 实际开发中Ctr+b,此处为了方便操作改为了Ctr+a
- 实际上没必要多开window,因为一次性只能看见一个window,通过多开pane一样可以实现多通道控制服务器.
(1) tmux:新建一个session,其中包含一个window,window中包含一个pane,pane里打开了一个shell对话框。
(2) 按下Ctrl + a后手指松开,然后按%:将当前pane左右平分成两个pane。
(3) 按下Ctrl + a后手指松开,然后按"(注意是双引号"):将当前pane上下平分成两个pane。
(4) Ctrl + d:关闭当前pane;如果当前window的所有pane均已关闭,则自动关闭window;如果当前session的所有window均已关闭,则自动关闭session。
(5) 鼠标点击可以选pane。
(6) 按下ctrl + a后手指松开,然后按方向键:选择相邻的pane。
(7) 鼠标拖动pane之间的分割线,可以调整分割线的位置。
(8) 按住ctrl + a的同时按方向键,可以调整pane之间分割线的位置。
(9) 按下ctrl + a后手指松开,然后按z:将当前pane全屏/取消全屏。
(10) 退出tmux:按下ctrl + a后手指松开,然后按d:挂起当前session。
(11) 重新进入tmux:tmux a(attach):打开之前挂起的session。
(12) 按下ctrl + a后手指松开,然后按s:选择其它session。
方向键 —— 上:选择上一项 session/window/pane
方向键 —— 下:选择下一项 session/window/pane
方向键 —— 右:展开当前项 session/window
方向键 —— 左:闭合当前项 session/window
(13) 按下Ctrl + a后手指松开,然后按c(create):在当前session中创建一个新的window。
(14) 按下Ctrl + a后手指松开,然后按w:选择其他window,操作方法与(12)完全相同。(session目录展开式)
(15) 按下Ctrl + a后手指松开,然后按PageUp:翻阅当前pane内的内容。
(16) 鼠标滚轮:翻阅当前pane内的内容。
(17) 在tmux中选中文本时,需要按住shift键。(仅支持Windows和Linux,不支持Mac,不过该操作并不是必须的,因此影响不大)
(18) tmux中复制/粘贴文本的通用方式:
(1) 按下Ctrl + a后松开手指,然后按[
(2) 用鼠标选中文本,被选中的文本会被自动复制到tmux的剪贴板
(3) 按下Ctrl + a后松开手指,然后按],会将剪贴板中的内容粘贴到光标处
Linux的VIM命令(超强功能记事本)
vi 和vim 的区别
vim比vi功能更强大,但是vi可以用于docker容器的简单Linux终端环境中文本/脚本编辑。
vim常用操作
一般命令模式切换到编辑模式
1、i:进入插入模式。从目前光标处插入。
2、I(大写i):进入插入模式。从目前所在行的第一个非空格符处开始插入。
3、a:进入插入模式。从目前光标所在处的下一个字符处开始插入。
4、A:进入插入模式。从光标所在行的最后一个字符处开始插入。
5、o:进入插入模式。从目前光标处所在的下一行处插入新的一行。
6、O:进入插入模式。从目前光标所在处的上一行插入新的一行。
7、r:进入替换模式。替换光标所在处的那一个字符一次。
8、R:进入替换模式。一直替换光标所在处的字符,直到按下Esc键为止。
9、U:回退,撤销上一步操作。
10、Esc:退出编辑模式返回到一般模式。
二、从一般模式切换到命令行模式
上面的命令只是在vi编辑命令中使用
首先使用esc(键退出)->:(符号输入)->wq(保存退出)
:wq(保存编辑操作退出)
:wq!(保存编辑强制退出
一般命令模式切换到编辑模式
1、:w:把编辑好的数据写入到硬盘文件中。
2、:w!:当文件属性为“只读”时强制写入该文件。具体能不能写入还要看该文件的文件权限。
3、:q:离开vi。
4、:q!:如果修改过文件但不需要存储,使用“!”强制离开不保存文件。
5、:wq:保存后离开。
6、:wq!:强制保存后离开。
7、:w[filename]:将编辑的数据保存成以filename命名的文件,相当于另存为文件。
8、:r[filename]:在编辑的数据中读另一个文件的内容,即将filename文件的内容加载到光标所在行的后面。
9、:num1,num2w[filename]:将num1到num2的内容保存成文件名filename的文件。
10:、:set nu:显示行号,设置完成后将会在每一行的前缀显示行号。
11、:set nonu:取消行号。
功能:
(1) 命令行模式下的文本编辑器。
(2) 根据文件扩展名自动判别编程语言。支持代码缩进、代码高亮等功能。
(3) 使用方式:vim filename.文件类型
如果已有该文件,则打开它。
如果没有该文件,则打开个一个新的文件,并命名为filename
模式:
(1) 一般命令模式
默认模式。命令输入方式:类似于打游戏放技能,按不同字符,即可进行不同操作。可以复制、粘贴、删除文本等。
(2) 编辑模式
在一般命令模式里按下i,会进入编辑模式。
按下ESC会退出编辑模式,返回到一般命令模式。
(3) 命令行模式
在一般命令模式里按下:/?三个字母中的任意一个,会进入命令行模式。命令行在最下面。
可以查找、替换、保存、退出、配置编辑器等。
按下ESC会退出命令行模式,返回到一般命令模式。
一般命令模式下操作:
组合键:
ggdG:文本全删
%s/source_pattern/target_pattern/g:将全文source_pattern替换为target_pattern
(1) i:进入编辑模式
(2) ESC:进入一般命令模式
(3) h 或 左箭头键:光标向左移动一个字符
(4) j 或 向下箭头:光标向下移动一个字符
(5) k 或 向上箭头:光标向上移动一个字符
(6) l 或 向右箭头:光标向右移动一个字符
(7) n<Space>:n表示数字,按下数字后再按空格,光标会向右移动这一行的n个字符
(8) 0 或 功能键[Home]:光标移动到本行开头
(9) $ 或 功能键[End]:光标移动到本行末尾
(10) G:光标移动到最后一行
(11) :n 或 nG:n为数字,光标移动到第n行
(12) gg:光标移动到第一行,相当于1G
(13) n<Enter>:n为数字,光标向下移动n行
(14) /word:向光标之下寻找第一个值为word的字符串。
(15) ?word:向光标之上寻找第一个值为word的字符串。
(16) n:重复前一个查找操作可与(14)(15)搭配实现连续查找
(17) N:反向(上->下)重复前一个查找操作
(18) :n1,n2s/word1/word2/g:n1与n2为数字,在第n1行与n2行之间寻找word1这个字符串,并将该字符串替换为word2
(19) :1,$s/word1/word2/g:将全文的word1替换为word2
(20) :1,$s/word1/word2/gc:将全文的word1替换为word2,且在替换前要求用户确认。
(21) v:选中文本
(22) d:删除v选中的文本
(23) dd: 删除当前行
(24) y:复制v选中的文本
(25) yy: 复制当前行
(26) p: 将复制的数据在光标的下一个位置粘贴
(27) u:撤销(类比window的ctr+z)
(28) Ctrl + r:取消撤销(类比window的ctr+shift+z)
(29) 大于号 >:将v选中的文本整体向右缩进一次
(30) 小于号 <:将v选中的文本整体向左缩进一次
(31) :w 保存
(32) :w! 强制保存
(33) :q 退出
(34) :q! 强制退出
(35) :wq 保存并退出
(36) :set paste 设置成粘贴模式,取消代码自动缩进
(37) :set nopaste 取消粘贴模式,开启代码自动缩进
(38) :set nu 显示行号
(39) :set nonu 隐藏行号
(40) gg=G:将全文代码格式化(缩进等等)
(41) :noh 关闭查找关键词高亮
(42) Ctrl + q:当vim卡死时,可以取消当前正在执行的命令
异常处理:
异常原因:不可同时使用vim打开同一个文件。不可以将写权限同时给多个用户。
每次用vim编辑文件时,会自动创建一个.filename.swp的临时文件((缓存文件)。
如果打开某个文件时,该文件的swp文件已存在(已被打开加载进缓存),则会报错。此时解决办法有两种:
(1) 找到正在打开该文件的程序,并退出
(2) 直接删掉该swp文件即可
Shell命令(shell脚本可以直接在命令行中编写执行,例如:for等)
C++/Java能实现的功能,Shell脚本也可以实现,无非就是for,if,读处理写文件等等
shell脚本基础
shell脚本若需要#!则必须放在首行,若是首行是空格则不同版本下会有问题。
在#!之后,接一个路径名,这个路径名指定了一个解释脚本命令的程序。
echo (stdout/运行结果)==cout 运行结果
exitcode 0(真|正常运行) 1(假|运行出错)==return 0 1
- 每条命令都有exitcode(命令运行状态码):0真(正常运行),非0假(运行出错)。
- 非逻辑判断命令:存在stdout(结果输出),exitcode(运行状态)
- 逻辑判断命令:可能存在stdout,输出逻辑判断结果(1真,0假),存在exitcode,逻辑判断结果(0真,非0假)
- echo $?:查看命令运行状态码exitcode。
- echo:查看命令输出结果stdout
能在terminal看见输出结果的都为stdout命令(查看命令:cat,ls等)。
万无一失:
变量运用时:${变量}
字符串常量运用时:“字符串”
shell运行的5种方式
第一种使用绝对路径执行
第二种使用相对路径执行,如./的方式
第三种使用 sh命令来执行 格式 sh 脚本名 不需要执行权限 -x参数(显示执行过程)
第四种使用 . (空格)脚本名称的方式执行 不需要执行权限 . a.sh
第五种使用 source 脚本名称 不需要执行权限(主要用于生效配置文件)
概论
Terminal和bash是两回事奥,terminal是IO环境,BASH是命令解释与执行器,完全不一样
-
shell是我们通过命令行与操作系统沟通的语言。
-
shell语言不需要编译直接解释运行。
-
shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用。
-
-
AC Terminal中的命令行可以看成是一个“shell脚本在逐行执行”。
Linux中常见的shell脚本有很多种,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- zsh
- …
Linux系统中一般默认使用bash,所以接下来讲解bash中的语法。
文件开头需要写#! /bin/bash,指明bash为脚本解释器。
shell脚本的第一行指定脚本解释器,不过值得注意的是,当我们使用指定解释器运行脚本的时候
bash *.sh
sh *.sh
我们脚本文件中的第一行会失效,比如通过bash+文件名运行脚本的方式,这样即便我在文件中指定是sh解释器,结果依然会以bash解释器运行.
学习技巧
不要死记硬背,遇到含糊不清的地方,可以在AC Terminal里实际运行一遍。
脚本示例
新建一个test.sh文件,内容如下:
vim test.sh
#! /bin/bash
echo "Hello World!"
运行方式
作为可执行文件
acs@9e0ebfcd82d7:~$ chmod +x test.sh # 使脚本具有可执行权限
acs@9e0ebfcd82d7:~$ ./test.sh # 当前路径下执行
Hello World! # 脚本输出
acs@9e0ebfcd82d7:~$ /home/acs/test.sh # 绝对路径下执行
Hello World! # 脚本输出
acs@9e0ebfcd82d7:~$ ~/test.sh # 家目录路径下执行
Hello World! # 脚本输出
用解释器执行
bash或sh *.sh
sh优于bash
acs@9e0ebfcd82d7:~$ bash test.sh
Hello World! # 脚本输出
注释
单行注释
每行中#之后的内容均是注释。
# 这是一行注释
echo 'Hello World' # 这也是注释
多行注释
格式:
:<<start
end
:<<EOF
第一行注释
第二行注释
第三行注释
EOF
其中EOF可以换成其它任意字符串。例如:
:<<abc
第一行注释
第二行注释
第三行注释
abc
:<<!
第一行注释
第二行注释
第三行注释
!
linux shell脚本EOF妙用-----------向一个文件输入多行内容
定义变量
定义变量,不需要加$符号,例如:
声明即定义
name1='yxc' # 单引号定义字符串
name2="yxc" # 双引号定义字符串
name3=yxc # 也可以不加引号,同样表示字符串
字符串拼接
使用变量
使用变量,需要加上$符号,或者${}符号。花括号是可选的,主要为了帮助解释器识别变量边界。
name=yxc
echo $name # 输出yxc
echo ${name} # 输出yxc
echo ${name}acwing # 输出yxcacwing
只读变量
使用readonly或者declare可以将变量变为只读。
name=yxc
readonly name
declare -r name # 两种写法均可
name=abc # 会报错,因为此时name只读
删除变量
unset可以删除变量。
name=yxc
unset name
echo $name # 输出空行
变量类型
自定义变量(局部变量) 子进程不能访问的变量
环境变量(全局变量) 子进程可以访问的变量
自定义变量改成环境变量:
acs@9e0ebfcd82d7:~$ name=yxc # 定义变量
acs@9e0ebfcd82d7:~$ export name # 第一种方法
acs@9e0ebfcd82d7:~$ declare -x name # 第二种方法
环境变量改为自定义变量:
acs@9e0ebfcd82d7:~$ export name=yxc # 定义环境变量
acs@9e0ebfcd82d7:~$ declare +x name # 改为自定义变量
字符串
字符串可以用单引号,也可以用双引号,也可以不用引号。
单引号与双引号的区别:
- 单引号中的内容会原样输出,不会执行、不会取变量(单引号中包双引号无需使用反斜杠转义输出);
- 双引号中的内容可以执行、可以取变量;
name=yxc # 不用引号
echo 'hello, $name \"hh\"' # 单引号字符串,输出 hello, $name \"hh\"
echo "hello, $name \"hh\"" # 双引号字符串,输出 hello, yxc "hh"
单双引号可以相互包容并原样显示。
注意:实际应用时单包双/双包单,不可单包单,双包双,无意义。
获取字符串长度
name="yxc"
echo ${#name} # 输出3
提取子串
Shell字符串截取(非常详细)
name="hello, yxc"
echo ${name:0:5} # 提取从0开始的5个字符
如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:
${string: start :length}
其中,string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),length 是要截取的长度(省略的话表示直到字符串的末尾)。
默认变量
文件参数变量
在执行shell脚本时,可以向脚本传递参数。$1是第一个参数,$2是第二个参数,以此类推。特殊的,$0是文件名(包含路径)。例如:
创建文件test.sh:vim test.sh
#! /bin/bash
echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "第三个参数:"$3
echo "第四个参数:"$4
然后执行该脚本:
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./test.sh 1 2 3 4
文件名:./test.sh
第一个参数:1
第二个参数:2
第三个参数:3
第四个参数:4
$其他参数相关变量
- $?:获取上一条命令执行完后的return退出状态,0为正常,1为错误.
# 检查Shell命令的退出状态
if [ $? -eq 0 ]; then
echo "上条Shell命令执行成功"
else
echo "上条Shell命令执行失败"
fi
- $(command)和$`command`:获取command执行后输出的结果(可用变量存储)。
只有$(command)用()其他的输出用${}
数组
数组中可以存放多个不同类型的值,只支持一维数组,初始化时不需要指明数组大小。
数组下标从0开始。
定义声明
数组用小括号表示,元素之间用空格隔开。例如:
array=(1 abc "def" yxc)
也可以直接定义数组中某个元素的值:
先定义声明数组才能赋值使用数组
array[0]=1
array[1]=abc
array[2]="def"
array[3]=yxc
读取数组中某个元素的值
格式:
${array[index]}
例如:
array=(1 abc "def" yxc)
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
读取整个数组
格式:
*和@表示全部的意思
${array[@]} # 第一种写法
${array[*]} # 第二种写法
例如:
array=(1 abc "def" yxc)
echo ${array[@]} # 第一种写法
echo ${array[*]} # 第二种写法
数组长度
类似于字符串
${#array[@]} # 第一种写法
${#array[*]} # 第二种写法
例如:
array=(1 abc "def" yxc)
echo ${#array[@]} # 第一种写法
echo ${#array[*]} # 第二种写法
expr命令
使用变量,需要加上$符号,或者${}符号。花括号是可选的,主要为了帮助解释器识别变量边界。
expr命令用于求表达式的值,格式为:
expr 表达式
注意:expr需要配合``或者$()返回stdout运算结果。
表达式说明:
- 用空格隔开每一项
- 用反斜杠放在shell特定的字符前面(发现表达式运行错误时,可以试试转义)
- 对包含空格和其他特殊字符的字符串要用引号括起来
- expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真,stdout为1,否则为0。
- expr的exit code:如果为逻辑关系表达式,则结果为真,exit code为0,否则为1。
字符串表达式
- length STRING 返回STRING的长度
- index STRING CHARSET
CHARSET中任意单个字符在STRING中最前面的字符位置,下标从1开始。如果在STRING中完全不存在CHARSET中的字符,则返回0。 - substr STRING POSITION LENGTH
返回STRING字符串中从POSITION开始,长度最大为LENGTH的子串。如果POSITION或LENGTH为负数,0或非数值,则返回空字符串。
示例:
str="Hello World!"
echo `expr length "$str"` # ``不是单引号,表示执行返回该命令的stdout,输出12
echo `expr index "$str" aWd` # 输出7,下标从1开始
echo `expr substr "$str" 2 3` # 输出 ell
整数表达式(仅支持整数)
expr支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。
+ -
加减运算。两端参数会转换为整数,如果转换失败则报错。
* / %
乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。
() 可以改变优先级,但需要用反斜杠转义
示例:
a=3
b=4
echo `expr $a + $b` # 输出7
echo `expr $a - $b` # 输出-1
echo `expr $a \* $b` # 输出12,*需要转义
echo `expr $a / $b` # 输出0,整除
echo `expr $a % $b` # 输出3
echo `expr \( $a + 1 \) \* \( $b + 1 \)` # 输出20,值为(a + 1) * (b + 1)
逻辑关系表达式
- |
如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。 - &
如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。 - < <= = == != >= >
比较两端的参数,如果为true,则返回1,否则返回0。”==”是”=”的同义词。”expr”首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。 - () 可以改变优先级,但需要用反斜杠\转义
示例:
a=3
b=4
echo `expr $a \> $b` # 输出0,>需要转义
echo `expr $a '<' $b` # 输出1,也可以将特殊字符用引号引起来
echo `expr $a '>=' $b` # 输出0
echo `expr $a \<\= $b` # 输出1
c=0
d=5
echo `expr $c \& $d` # 输出0
echo `expr $a \& $b` # 输出3
echo `expr $c \| $d` # 输出5
echo `expr $a \| $b` # 输出3
read命令(配合while)
read命令用于从标准输入中读取单行数据。当读到文件结束符(ctr+d)时,exit code为1,否则为0。
参数说明
- -p: 后面可以接提示信息
- -t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令
实例:
acs@9e0ebfcd82d7:~$ read name # 读入name的值
acwing yxc # 标准输入
acs@9e0ebfcd82d7:~$ echo $name # 输出name的值
acwing yxc #标准输出
acs@9e0ebfcd82d7:~$ read -p "Please input your name: " -t 30 name # 读入name的值,等待时间30秒
Please input your name: acwing yxc # 标准输入
acs@9e0ebfcd82d7:~$ echo $name # 输出name的值
acwing yxc # 标准输出
示例,文件结束符为Ctrl+d,输入文件结束符后read指令返回false。
while read name
do
echo ${name}
done
实战时可以用于逐行读取并操作处理文件内容
cat xxx.filetype | while read name
do
echo ${name}
done
grep yyy xxx.filetype | while read name
do
echo ${name}
done
echo命令
echo用于输出字符串和stdout。命令格式:
echo STRING
显示普通字符串
echo "Hello AC Terminal"
echo Hello AC Terminal # 引号可以省略
显示转义字符
echo "\"Hello AC Terminal\"" # 注意只能使用双引号,如果使用单引号,则不转义原样输出
echo \"Hello AC Terminal\" # 也可以省略双引号
显示变量
name=yxc
echo "My name is $name" # 输出 My name is yxc
显示换行
echo -e "Hi\n" # -e 开启转义
echo "acwing"
输出结果:
Hi
acwing
显示不换行
echo -e "Hi \c" # -e 开启转义 \c 不换行
echo "acwing"
输出结果:
Hi acwing
显示结果定向至文件
echo "Hello World" > output.txt # 将内容以覆盖的方式输出到output.txt中
原样输出字符串,不进行转义或取变量(用单引号)
name=acwing
echo '$name\"'
输出结果
$name\"
显示命令的执行结果
定义命令变量
C=`command`
echo ${C}
echo `date`
输出结果:
Wed Sep 1 11:45:33 CST 2021
printf命令
printf命令用于格式化输出,类似于C/C++中的printf函数。
默认不会在字符串末尾添加换行符。
命令格式:
printf format-string [arguments...]
用法示例
脚本内容:
printf "%10d.\n" 123 # 占10位,右对齐
printf "%-10.2f.\n" 123.123321 # 占10位,保留2位小数,左对齐
printf "My name is %s\n" "yxc" # 格式化输出字符串
printf "%d * %d = %d\n" 2 3 `expr 2 \* 3` # 表达式的值作为参数
输出结果:
123.
123.12 .
My name is yxc
2 * 3 = 6
test命令与判断符号[]
因为test命令是逻辑判断命令所以需要echo $?查看命令exitcode确定逻辑判断结果
逻辑运算符&&和||
- && 表示与,|| 表示或
- 二者具有短路原则:
左结合性:先左后右,符合条件,立马结束。
expr1 && expr2:当expr1为假时,直接忽略expr2
expr1 || expr2:当expr1为真时,直接忽略expr2
- 表达式的exit code为0,表示真;为非零,表示假。(与C/C++中的定义相反)
test命令
在命令行中输入man test,可以查看test命令的用法。
test命令用于判断文件类型,以及对变量做比较。
test命令用exit code返回结果,而不是使用stdout。0表示真,非0表示假。
例如:
test 2 -lt 3 # 为真,返回值为0
echo $? # 输出上个命令的返回值,输出0
acs@9e0ebfcd82d7:~$ ls # 列出当前目录下的所有文件
homework output.txt test.sh tmp
acs@9e0ebfcd82d7:~$ test -e test.sh && echo "exist" || echo "Not exist"
exist # test.sh 文件存在
acs@9e0ebfcd82d7:~$ test -e test2.sh && echo "exist" || echo "Not exist"
Not exist # testh2.sh 文件不存在
文件类型判断
命令格式:
test -e filename # 判断文件是否存在
文件权限判断
命令格式:
test -r filename # 判断文件是否可读
整数间的比较
命令格式:
test $a -eq $b # a是否等于b
字符串比较
多重条件判定
命令格式:
test -r filename -a -x filename
判断符号[]
[]与test用法几乎一模一样,更常用于if语句中。另外[[]]是[]的加强版,支持的特性更多。
例如:
[ 2 -lt 3 ] # 为真,返回值为0
echo $? # 输出上个命令的返回值,输出0
acs@9e0ebfcd82d7:~$ ls # 列出当前目录下的所有文件
homework output.txt test.sh tmp
acs@9e0ebfcd82d7:~$ [ -e test.sh ] && echo "exist" || echo "Not exist"
exist # test.sh 文件存在
acs@9e0ebfcd82d7:~$ [ -e test2.sh ] && echo "exist" || echo "Not exist"
Not exist # testh2.sh 文件不存在
注意:
[]内的每一项都要用空格隔开
中括号内的变量,最好用双引号括起来:[“$变量”]
中括号内的常数,最好用单或双引号括起来[‘常数’]
避免因为变量值的空格导致识别为多个参数,字符串加引号辅助识别变量边界
例如:
name="acwing yxc"
[ $name == "acwing yxc" ] # 错误,等价于 [ acwing yxc == "acwing yxc" ],参数太多
[ "$name" == "acwing yxc" ] # 正确
判断语句
if…then形式
类似于C/C++中的if-else语句。
单层if
命令格式:
if condition
then
语句1
语句2
...
fi
示例:
a=3
b=4
if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]
then
echo ${a}在范围内
fi
输出结果:
3在范围内
单层if-else
命令格式
if condition
then
语句1
语句2
...
else
语句1
语句2
...
fi
示例:
a=3
b=4
if ! [ "$a" -lt "$b" ]
then
echo ${a}不小于${b}
else
echo ${a}小于${b}
fi
输出结果:
3小于4
日期前缀非零判断及消除
read day
if [ `echo ${day}|grep ^0` ]
then
day1=${day:1:1}
else
day1=${day}
fi
echo ${day1}
多层if-elif-elif-else
命令格式
if condition
then
语句1
语句2
...
elif condition
then
语句1
语句2
...
elif condition
then
语句1
语句2
else
语句1
语句2
...
fi
示例:
a=4
if [ $a -eq 1 ]
then
echo ${a}等于1
elif [ $a -eq 2 ]
then
echo ${a}等于2
elif [ $a -eq 3 ]
then
echo ${a}等于3
else
echo 其他
fi
输出结果:
其他
case…esac形式
类似于C/C++中的switch语句。
命令格式
case $变量名称 in
值1)
语句1
语句2
...
;; # 类似于C/C++中的break
值2)
语句1
语句2
...
;;
*) # 类似于C/C++中的default
语句1
语句2
...
;;
esac
示例:
a=4
case $a in
1)
echo ${a}等于1
;;
2)
echo ${a}等于2
;;
3)
echo ${a}等于3
;;
*)
echo 其他
;;
esac
输出结果:
其他
循环语句
for…in…do…done
命令格式:
for var in val1 val2 val3
do
语句1
语句2
...
done
将输入参数输出:多个输入参数用空格间隔。
也可用cat和grep的stdout结果作为输入值
acs@f2a8b5544fd2:~$ cat testh.sh
all=`grep i *.t`
for t in $all
do
echo $t
done
all=`cat *.t`
for t in $all
do
echo $t
done
acs@f2a8b5544fd2:~$ sh testh.sh
test.t:i
test1.t:i
i
i
示例1,输出a 2 cc,每个元素一行:
for i in "a" "2" "cc"
do
echo ${i}
done
示例2,输出当前路径下的所有文件名,每个文件名一行:
`command`==$(command):返回command命令的stdout
for file in `ls`
do
echo $file
done
示例3,输出1-10
for i in $(seq 1 10)
do
echo $i
done
示例4,使用{1…10} 或者 {a…z}
for i in {a..z}
do
echo $i
done
for ((…;…;…)) do…done
命令格式:
for ((expression; condition; expression))
do
语句1
语句2
done
示例,输出1-10,每个数占一行:
for ((i=1; i<=10; i++))
do
echo ${i}
done
while…do…done循环
命令格式:
while condition
do
语句1
语句2
...
done
示例,文件结束符为Ctrl+d,输入文件结束符后read指令返回false。
while read name
do
echo ${name}
done
实战时可以用于逐行读取并操作处理文件内容
cat xxx.filetype | while read name
do
echo ${name}
done
grep yyy xxx.filetype | while read name
do
echo ${name}
done
until…do…done循环
当条件为真时结束。
命令格式:
until condition
do
语句1
语句2
...
done
示例,当用户输入yes或者YES时结束,否则一直等待读入。
until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]
do
read -p "Please input yes/YES to stop this program: " word
done
break命令
跳出当前一层循环,注意与C/C++不同的是:break不能跳出case语句。
break跳出for循环,;;跳出case语句。
示例
while read name
do
for ((i=1;i<=10;i++))
do
case $i in
8)
break
;;
*)
echo $i
;;
esac
done
done
该示例每读入非EOF的字符串,会输出一遍1-7。
该程序可以输入Ctrl+d文件结束符来结束,也可以直接用Ctrl+c杀掉该进程。
continue命令
跳出当前循环。
示例:
for ((i=1;i<=10;i++))
do
if [ `expr $i % 2` -eq 0 ]
then
continue
fi
echo $i
done
该程序输出1-10中的所有奇数。
死循环的处理方式
如果AC Terminal可以打开该程序,则输入Ctrl+c即可。
否则可以直接关闭进程:
- 使用top命令找到进程的PID
- 输入kill -9 PID即可关掉此进程
kill -9 PID强制关闭进程
函数
Shell脚本之函数
bash中的函数类似于C/C++中的函数,但return的返回值与C/C++不同,返回的是exit code,取值为0-255,0表示正常结束(return 0)。
如果想获取函数的输出结果,可以通过echo输出到stdout中,然后通过$(function_name)来获取stdout中的结果。
函数的return值可以通过$?来获取。
函数调用方式
- 直接调用函数不需要返回值则直接用func_name就行
- $(command):得到command命令的stdout(cout)
- $?;得到command命令的exitcode(return)
命令格式:
[function] func_name() { # function关键字可以省略
语句1
语句2
...
}
不获取 return值和stdout值
示例
直接调用函数不需要返回值则直接用func_name就行
func() {
name=yxc
echo "Hello $name"
}
func
输出结果:
Hello yxc
获取 return值和stdout值
不写return时,默认return 0。
示例
$(command):得到command命令的stdout(cout)
$?;得到command命令的exitcode(return)
直接调用函数不需要返回值则直接用func_name就行
func() {
name=yxc
echo "Hello $name"
return 123
}
output=$(func)
ret=$?
echo "output = $output"
echo "return = $ret"
输出结果:
output = Hello yxc
return = 123
函数的输入参数
在函数内,$1表示第一个输入参数,$2表示第二个输入参数,依此类推。
注意:函数内的$0仍然是文件名,而不是函数名。
示例:
func() { # 递归计算 $1 + ($1 - 1) + ($1 - 2) + ... + 0
word=""
while [ "${word}" != 'y' ] && [ "${word}" != 'n' ]
do
read -p "要进入func($1)函数吗?请输入y/n:" word
done
if [ "$word" == 'n' ]
then
echo 0
return 0
fi
if [ $1 -le 0 ]
then
echo 0
return 0
fi
sum=$(func $(expr $1 - 1))
echo $(expr $sum + $1)
}
echo $(func 10)
输出结果:
55
函数内的局部变量
可以在函数内定义局部变量,作用范围仅在当前函数内。
可以在递归函数中定义局部变量。
命令格式:
local 变量名=变量值
例如:
#! /bin/bash
func() {
local name=yxc
echo $name
}
func
echo $name
输出结果:
yxc
第一行为函数内的name变量,第二行为函数外调用name变量,会发现此时该变量不存在。
exit命令
exit命令用来退出当前shell脚本进程,并返回一个退出状态;使用$?可以接收这个退出状态exitcode。
exit命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是 0。
exit退出状态只能是一个介于 0~255 之间的整数,其中只有 0 表示成功,其它值都表示失败。
示例:
创建脚本test.sh,内容如下:
#! /bin/bash
if [ $# -ne 1 ] # 如果传入参数个数等于1,则正常退出;否则非正常退出。
then
echo "arguments not valid"
exit 1
else
echo "arguments valid"
exit 0
fi
执行该脚本:
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./test.sh acwing
arguments valid
acs@9e0ebfcd82d7:~$ echo $? # 传入一个参数,则正常退出,exit code为0
0
acs@9e0ebfcd82d7:~$ ./test.sh
arguments not valid
acs@9e0ebfcd82d7:~$ echo $? # 传入参数个数不是1,则非正常退出,exit code为1
1
文件重定向
每个进程默认打开3个文件描述符:
- stdin标准输入,从命令行读取数据,文件描述符为0
- stdout标准输出,向命令行输出数据,文件描述符为1
- stderr标准错误输出,向命令行输出数据,文件描述符为2
可以用文件重定向将这三个文件重定向输入到其他文件中。
>是覆盖file中内容,>>是将内容从末尾追加到file中
单独使用> /file.filetype可以起到新建/清空文件的效果。
注意:>和>>只能新建文件但是不能新建目录。 输入和输出重定向
echo -e "Hello \c" > output.txt # 将stdout重定向到output.txt中
echo "World" >> output.txt # 将字符串追加到output.txt中
read str < output.txt # 从output.txt中读取字符串
echo $str # 输出结果:Hello World
同时重定向stdin和stdout
创建bash脚本:
#! /bin/bash
read a
read b
echo $(expr "$a" + "$b")
创建input.txt,里面的内容为:
3
4
执行命令:
acs@9e0ebfcd82d7:~$ chmod +x test.sh # 添加可执行权限
acs@9e0ebfcd82d7:~$ ./test.sh < input.txt > output.txt # 从input.txt中读取内容,将输出写入output.txt中
acs@9e0ebfcd82d7:~$ cat output.txt # 查看output.txt中的内容
7
引入外部脚本(bash解释器可执行)
类似于C/C++中的include操作,bash也可以引入其他文件中的代码。
语法格式:
. filename # 注意点和文件名之间有一个空格
或
source filename
示例
创建test1.sh,内容为:
#! /bin/bash
name=yxc # 定义变量name
然后创建test2.sh,内容为:
#! /bin/bash
source test1.sh # 或 . test1.sh
echo My name is: $name # 可以使用test1.sh中的变量
执行命令:
acs@9e0ebfcd82d7:~$ chmod +x test2.sh
acs@9e0ebfcd82d7:~$ ./test2.sh
My name is: yxc
Shell自定义
ssh(远程登录连接并加密传输信息)
ssh登录(公网IP)
远程建立session会话,SSH加密信息传输内容。
SSH:Secure Shell,较可靠、专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。最常见的我们可以用它来登录我们的Linux服务器。
Linux:网络操作系统
Linux是基于网络的,诞生于网络。
远程连接上SSH,你就可以轻松操控远在千里之外的Linux服务器,只要有相应的权限,几乎和坐在物理机面前没有区别,哪怕网速很糟糕,实际只是一些加密的字符在传送,shell命令传输需要的带宽很小。
基本用法
远程登录服务器:
ssh user@hostname
账号:(一台服务器(一个公网IP)可以有多个账号)
- user: 服务器用户名
- hostname: 服务器公网IP地址或域名
第一次登录时会提示:
The authenticity of host '123.57.47.211 (123.57.47.211)' can't be established.
ECDSA key fingerprint is SHA256:iy237yysfCe013/l+kpDGfEG9xxHxm0dnxnAbJTPpG8.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
输入yes,然后回车即可。
这样会将该服务器的信息记录在~/.ssh/known_hosts文件中。
然后输入密码即可登录到远程服务器中。
默认登录端口号为22。如果想登录某一特定端口:
ssh user@hostname -p 22
配置文件
创建文件 ~/.ssh/config。
然后在文件中输入:
Host myserver1
HostName IP地址或域名
User 用户名
Host myserver2
HostName IP地址或域名
User 用户名
之后再使用服务器时,可以直接使用别名myserver1、myserver2。
密钥登录
SSH登录及其原理详解
SSH 共有两种登录方式:
口令验证登录
-
服务器生成公钥和私钥
-
客户端发起连接请求,服务器将公钥发给客户端
-
客户端生成口令(服务器密码),并用服务器发来的公钥加密,发送给服务器
-
服务器通过私钥解密,拿到口令(服务器密码)
-
如果正确则认证成功
密钥验证登录
- 客户端生成公钥和私钥,将公钥提前部署在服务器上
- 客户端发起连接请求
- 服务器随机生成一个字符串,用本地的公钥加密,发送给客户端
- 客户端通过私钥解密,将解密后的字符串发送给服务器
- 服务器验证本地字符串和客户端发来的字符串的一致性,如果通过,则认证成功
创建密钥:
ssh-keygen
然后一直回车即可。
执行结束后,~/.ssh/目录下会多两个文件:
- id_rsa:私钥
- id_rsa.pub:公钥
之后想免密码登录哪个服务器,就将公钥传给哪个服务器即可。
例如,想免密登录myserver服务器。则将公钥中的内容,复制到myserver中的~/.ssh/authorized_keys文件里即可。
也可以使用如下命令一键添加公钥到远程服务器:
前提:配置好.ssh/config中的信息。myserver为对应的
ssh-copy-id myserver
执行命令
命令格式:
ssh user@hostname command
例如:
ssh user@hostname ls -a
或者
# 单引号中的$i可以求值
ssh myserver 'for ((i = 0; i < 10; i ++ )) do echo $i; done'
或者
# 双引号中的$i不可以求值
ssh myserver "for ((i = 0; i < 10; i ++ )) do echo $i; done"
总结
scp跨服务器传文件(myserver(别名)=username@IP/域名)
前提:源和端网络能通信
主机上ping一下IP看看网络是否能通信。
destination必须是绝对路径
source是本地主机文件可以用相对路径
scp source ------> destination
scp source username@IP/域名:destination
或
scp username@IP/域名:source destination
前提:配置SSH远程登录
scp 命令是用于通过 SSH 协议安全地将文件复制到远程系统和从远程系统复制文件到本地的命令。使用 SSH 意味着它享有与 SSH相同级别的数据加密,因此被认为是跨两个远程主机传输文件的安全方式。
基本用法
命令格式:
scp source destination
将source路径下的文件复制到destination中
一次复制多个文件:
scp source1 source2 destination
复制文件夹:
scp -r ~/tmp myserver:/home/user/
将本地家目录中的tmp文件夹复制到myserver(别名)服务器中的/home/user/目录下。
默认:myserver为/home/user/目录下。
scp -r ~/tmp myserver:homework/
将本地家目录中的tmp文件夹复制到myserver服务器中的~/homework/目录下。
scp -r myserver:homework .
将myserver服务器中的~/homework/文件夹复制到本地的当前路径下。
指定服务器的端口号:
scp -P 22 source1 source2 destination
注意: scp的-r -P等参数尽量加在source和destination之前。
使用scp配置其他远程服务器的vim和tmux
scp ~/.vimrc ~/.tmux.conf myserver:
date命令简介
`date空格 ‘+日期格式’`
- lastdata=
date -d "-3 day" +%Y%m%d
:默认当前日期减去三天的YYYYMMDD
- - -d参数 ,说明要显示的是后面的字符串表示的时间,“1 day ago” 说明是1天前的时间。
#! /bin/bash
first=$1
second=$2
while [ "$first" != "$second" ]
do
echo $first
first=`date -d "-1 days ago ${first}" +%Y%m%d`
done
样例:
遍历输出日期区间
或
注意:中间是两个英文句号
for lastdata in {20221201…20221213}
do
…
done
lastdate=`date -d "-6 day" +%Y%m%d`
currdate=`date +%Y%m%d`
echo SMS
for ((monday=${lastdate}; monday<=${currdate}; monday++))
do
......
done
管道、环境变量与常用命令
管道
概念
能在terminal看见输出结果的都为stdout命令(查看命令:cat,ls等)。
管道类似于文件重定向,从左到右执行,可以将前一个命令的stdout重定向到下一个命令的stdin。
要点
- 管道命令仅处理stdout,会忽略stderr。
- 管道右边的命令必须能接受stdin。
- 多个管道命令可以串联。
与文件重定向的区别
- 文件重定向左边为命令,中间为<>,右边为文件。
- 管道左右两边均为命令,左边有stdout,中间为|,右边有stdin。
举例
统计当前目录下所有python文件的总行数,其中find、xargs、wc等命令可以参考常用命令这一节内容。
find . -name '*.txt' | xargs cat | wc -l
首先寻找当前目录下所有txt文件,然后通过xargs将stdout转化为文件参数给cat,,最后由wc将cat展示的文件内容进行处理输出。
环境变量
环境变量
概念
Linux系统中会用很多环境变量来记录配置信息。
环境变量类似于全局变量,可以被各个进程访问到。我们可以通过修改环境变量来方便地修改系统配置。
查看
列出当前环境下的所有环境变量:
env # 显示当前用户的变量
set # 显示当前shell的变量,包括当前用户的变量;
export # 显示当前导出成用户变量的shell变量
输出某个环境变量的值:
echo $PATH
修改
环境变量的定义、修改、删除操作可以参考shell语法——变量这一节的内容。
vim ~/.bashrc
为了将对环境变量的修改应用到未来所有环境下,可以将修改命令放到~/.bashrc文件中。
修改完~/.bashrc文件后,记得执行source ~/.bashrc,来将修改应用到当前的bash环境下。
为何将修改命令放到~/.bashrc,就可以确保修改会影响未来所有的环境呢?
- 每次启动bash,都会先执行~/.bashrc。
- 每次ssh登陆远程服务器,都会启动一个bash命令行给我们。
- 每次tmux新开一个pane,都会启动一个bash命令行给我们。
- 所以未来所有新开的环境都会加载我们修改的内容。
常见环境变量
可用echo ${环境变量},查看对应环境变量的数值。
- HOME:用户的家目录。
- PATH:可执行文件(shell命令,软件自定义命令等等)的存储路径。路径与路径之间用:分隔。当某个可执行文件同时出现在多个路径中时,会选择从左到右数第一个路径中的执行。下列所有存储路径的环境变量,均采用从左到右的优先顺序。
PATH指向的路径存储着对应可执行命令文件(例如:bin目录)
可以修改~/.bashrc文件,将自己写的命令行程序放在PATH环境变量中,这样就可以使用自己的命令了
linux下自定义命令的几种方式
linux自定义命令
- LD_LIBRARY_PATH:用于指定动态链接库(.so文件)的路径,其内容是以冒号分隔的路径列表。
- C_INCLUDE_PATH:C语言的头文件路径,内容是以冒号分隔的路径列表。 - CPLUS_INCLUDE_PATH:CPP的头文件路径,内容是以冒号分隔的路径列表。 - PYTHONPATH:Python导入包的路径,内容是以冒号分隔的路径列表。 - JAVA_HOME:jdk的安装目录。 - CLASSPATH:存放Java导入类的路径,内容是以冒号分隔的路径列表。
常用命令
系统状况
top:查看所有进程的信息(Linux的任务管理器)
- 打开后,输入M(MEMORY):按使用内存排序
- 打开后,输入P(CPU):按使用CPU排序
- 打开后,输入q(QUIT):退出
df -h:查看硬盘使用情况
free -h:查看内存使用情况
du -sh:查看当前目录下文件占用的总硬盘空间。
- du -h:显示目录中文件的具体大小,分别以对应的KB,MB,GB范围为单位
- du -sh *:显示当前文件夹内各个文件大小
du -h --max-depth=1:当前文件夹内每个文件的大小
ps aux:查看所有进程
ps -ef 指令详解
ps -ef | grep 进程名配合食用
kill -9 pid:强制杀死编号为pid的进程
- 传递某个具体的信号:kill -s SIGTERM pid
netstat -nt:查看所有网络连接
w:列出当前登陆的用户
ping www.baidu.com:检查是否连网
文件权限
d r w x | r w x | r w x
自己|同组|其他
d:是否为目录,r:是否可读,w:是否可写,x:是否可执行
ll:查看当前目录全部文件的权限
chmod:修改文件权限
- chmod +x xxx:给xxx添加可执行权限
- chmod -x xxx:去掉xxx的可执行权限
- chmod 777 xxx:将xxx的权限改成777(全可读写执行)
二进制形式赋权,三位=0~7,7表示赋予全部权限 - chmod 777 xxx -R:递归修改整个文件夹的权限
文件编码方式
file 文件:查看文件编码格式
file [-bcLvz][-f <名称文件>][-m <魔法数字文件>…][文件或目录…]
中文乱码的原因:编码和解码不一致
只有中文会出现乱码问题
文件检索
输出当前目录下的全部sh文件包含“hello”的行。
文本检索
grep实用案例
(查询文本)grep xxx:从stdin中读入若干行数据,如果某行中包含xxx,则输出该行(逐行输出);否则忽略该行。
默认匹配模式是模糊匹配
-c:统计符合字符串条件的行数
-v:显示不包括文本的所有信息
-w:精准匹配完整单词(同行完整单词分隔符可为逗号和空格)
可以配合ps,ls等stdout命令食用:查询进程/目录中是否存在对应进程和文件。
grep详解
Linux命令 zgrep
使用zgrep命令可以在压缩文件中调用grep按正则表达式来搜索
zgrep -hw
grep xxx ./*.filetype:将path下的全部filetype文件内容进行查询匹配逐行输出=》文件名:匹配列
(分析文本)wc:统计行数、单词数、字节数
- 既可以从stdin中直接读入内容;也可以在命令行参数中传入文件名列表;
- wc -l:统计行数
- wc -w:统计单词数
- wc -c:统计字节数
grep xxx | wc -l
awk xxx | wc -l
或
wc -l xxx.file
cut:分割一行内容(-d:列,-c:字符)
- 从stdin中读入多行数据
- echo $PATH | cut -d ‘:’ -f 3,5:输出PATH用:分割后第3、5列数据
- echo $PATH | cut -d ‘:’ -f 3-5:输出PATH用:分割后第3-5列数据
- echo $PATH | cut -c 3,5:输出PATH的第3、5个字符
- echo $PATH | cut -c 3-5:输出PATH的第3-5个字符
sort:将每行内容按字典序排序
- 可以从stdin中读取多行数据
- 可以从命令行参数中读取文件名列表
文件检索
find /path/to/directory/ -name ‘*.py’:搜索/path/to/directory/文件路径下的所有*.py文件
- 直接find则是查看当前目录的文件结构。
- 一般直接:find . -name ’ '查找当前目录下的对应name文件
which:会在环境变量$PATH设置的目录里查找符合条件的可执行文件。
find只能查文件,which只可以查可执行命令(ls,cat,软件自定义命令等)
tree:展示当前目录的文件结构
- tree /path/to/directory/:展示某个目录的文件结构
- tree -a:展示全部文件,包括隐藏文件
ag xxx:搜索当前目录下的所有文件,检索xxx字符串
xargs:将stdin中的数据用空格或回车分割成命令行参数
- find . -name ‘*.py’ | xargs cat | wc -l:统计当前目录下所有python文件的总行数
查看文件内容
全部输出
cat:一次性输出文件全部内容
vim:增删改查文件全部内容
部分输出
more:浏览文件内容
- 回车:下一行
- 空格:下一页
- b:上一页
- q:退出
less:与more类似,功能更全
- 回车:下一行
- y:上一行
- Page Down:下一页
- Page Up:上一页
- q:退出
head -3 xxx:展示xxx的前3行内容
- 同时支持从stdin读入内容(可接管道命令)
tail -3 xxx:展示xxx末尾3行内容
- 同时支持从stdin读入内容
tail -f filename 会把 filename 文件里的最尾部十行的内容显示在屏幕上,并且不断刷新follow跟踪,只要 filename 更新就可以看到最新的文件内容。
替换文本内容(sed -i “s/原内容/替换内容/g” file.filetype)
常见用法:
首先写一个tmpl模板文件然后写一个脚本基于tmpl模板文件替换占位符传参。
sh 脚本.sh 变量参数
sed -i "s/\${tmpl参数占位符}/"${变量参数}"/g" tmpl复制份
替换特殊字符(利用反斜杠)
反斜杠用法
awk文本操作( awk [选项] ‘{脚本命令}’ 文件名)
Linux awk命令详解
linux之awk超详解
linux awk数组操作详细介绍
cat获得文件内容,grep分析提取文件内容,awk解析操作需求内容的每一行。
awk将"作为文本分隔符,然后提取第四列作为sum数组的定位下标并将其对应的数组元素值加一,处理完全部内容后,END最后用for循环逐行输出数组值(一次输出占一行)。
无序:cat XXX.filetype | grep "yyy" | awk -F'"' '{sum[$4]+=1} END {for(k in sum) print k ":" sum[k]}'
有序(已知:k<=100):cat XXX.filetype | grep "yyy" | awk -F'"' '{sum[$4]+=1} END {for(k=1;k<=100;k++) if (sum[k]>0) print k ":" sum[k]}'
- awk 中的数组不必提前声明,也不必声明大小。数组元素用 0 或空串来初始化。
- $n 指定分隔的第n个字段,如$1、$3分别表示第1、第3列.$0代表输入整行内容。
- 若awk的{}中要用定义的变量则"‘$变量’"
awk -F, '{SUM['$number']=SUM['$number']+1} END {for (i in SUM) print i,SUM[i]} '
- for…in 输出,因为数组是关联数组,默认是无序的。所以通过for…in 得到是无序的数组。如果需要得到有序数组,需要通过下标获得(注意:数组下标是从1开始,与c数组不一样)。
无序:for(k in arry),有序:for(k=1;k<=len;k++)
print k : arry[k]
注意(万物皆字符串,一劳永逸):
若数组内使用自定义变量则AWK的数组下标直接用"‘’"来声明字符串变量,防止变量为字符串非数值作为下标导致出错。
未使用双引号则默认为数值,反之可为字符串类型(双引号需要在变量最外侧标明)。
'{SUM["'$number'"]=SUM["'$number'"]+$4}'
若报错则说明检索的文本没有对应属性导致SUM[]中下标为空。
用户相关
history:展示当前用户的历史操作。内容存放在~/.bash_history中
whoami:查询当前用户类型:是否为root
clear:清屏
工具
哈希值:原文为key,对应转化为哈希值value
md5sum:计算md5哈希值(将文件内容转为唯一32位字符,文件内容变化一点,则对应32位字符也会变化)
- 可以从stdin读入内容
- 也可以在命令行参数中传入文件名列表;
time command:统计command命令的执行时间
ipython3:交互式python3环境。可以当做计算器,或者批量管理文件。
- ! echo “Hello World”:!表示执行shell脚本
watch -n 0.1 command:每0.1秒执行一次command命令
tar:压缩文件
- tar -zcvf xxx.tar.gz /path/to/file/*:压缩/path/to/file/*文件为xxx.tar.gz
- tar -zxvf xxx.tar.gz:解压缩为原文件类型,默认为原文件名
diff xxx yyy:查找文件xxx与yyy的不同点
安装软件(权限不够,sudo来凑)
- sudo command:以root身份执行command命令
root在linux中具有无上权限,啥都可以做
- apt-get install xxx:安装软件
- pip install xxx --user --upgrade:安装python包
常用命令组合
全部查看命令都常用:ctr+f:查看
- ls -lrt:目录新增文件时,根据时间排序快速查找对应新增文件,最底的就是新增文件。
ls -lrt 表示 按修改时间 倒序 列出当前工作目录下的所有文件的详细信息 - cat 文件名 | wc -l:统计文件数据行数
cat /* | wc -l:统计某目录下全部文件数据行数 - nohup command &:将command挂载到服务器运行,脱离终端运行(进程无终端指向也会运行,服务端shell进程的运行不受本地终端的干扰)。
一般配合tail -f nohup.out查看实时后台进程运行日志食用
或ps -ef | grep command查看服务器后台挂载的命令是否还在运行。 - ps -ef | grep 进程名:配合食用查询服务器对应进程
- XXX.sh文件中可以写sh XXX.sh语句,从而可以实现一个sh文件批量启动多个sh文件。
- du -h:显示目录中文件的具体大小,分别以对应的KB,MB,GB范围为单位
- du *:显示目录中文件大小,字节B为单位
实战注意事项
脚本中的nohup
nohup命令若是出现在for或者while循环中注意控制数量,防止服务端挂载过多线程。
while true
do
# 跑中:zgrep -hw $number ./xxxx/yyyy.log.gz >> ./zzzz${currdate}/$number.log
# 跑完结果:grep --color=auto zgrep
threadnum=`ps -ef | grep zgrep | awk '{print $11}' | sort | uniq | wc -l `
# 实际上因为特殊的主机服务端,会自动对挂载的进程,产生多个线程提升速度,所以用sort和uniq对#11=number排序去重后wc计算实际挂载数量。
echo $threadnum
# zgrep进程数是否大于10
if [ $threadnum -gt 10 ]; then
# 十一条zgrep还在跑则当前进程停一下等等,防止服务端挂载过多线程
sleep 120
else
# 少于十一条zgrep则继续挂载zgrep进程
break
fi
done
for和while
for和while可以以空格或者回车为分割符,逐个循环读取(echo,``,cat,grep)stdout中的值并在循环体内操作。
上述内容中有介绍。
读文本,压缩文件,日志等
# 类似cat,同时解压并输出内容
zcat app.log.gz
# 类似grep,同时解压并查找内容
zgrep -m 10 ERROR app.log.gz
# 类似less,同时解压并查看内容
zless app.log.gz
less:与more类似,功能更全
- 回车:下一行
- y:上一行
- Page Down:下一页
- Page Up:上一页
- q:退出
less好处:另开界面,不会占据输入命令的界面且限量显示文本。
识别自定义别名命令(alias)
alias rm='Are you crazy?'
单双引号
字符串
字符串可以用单引号,也可以用双引号,也可以不用引号。
单引号与双引号的区别:
- 单引号中的内容会原样输出,不会执行、不会取变量;
- 双引号中的内容可以执行、可以取变量;
name=yxc # 不用引号
echo 'hello, $name \"hh\"' # 单引号字符串,输出 hello, $name \"hh\"
echo "hello, $name \"hh\"" # 双引号字符串,输出 hello, yxc "hh"
单双引号可以相互包容并原样显示,无需转义字符。
可用于在字符串变量命令中声明字符串。
多用于单引号包双引号,这样可以执行字符串中的命令。
例如:若数组内使用自定义变量则AWK的数组下标直接用"‘’"来使用变量,防止变量为字符串非数值作为下标导致出错。
未使用双引号则默认为数值,反之可为字符串类型(万物皆字符串,一劳永逸)。
'{SUM["$number"]=SUM["$number"]+$4}'
实战经验
C++/Java能实现的功能,Shell脚本也可以实现,无非就是for,if,读处理写文件等等
WC弊端(回车记为一行)
文本内容追加>>符号
每次文件内容追加默认另起一行.。
expect脚本远程登录、远程执行命令和脚本传参简单用法
expect就是一个维持源端主机shell命令通信的桥梁,建立连接后,在本地的源主机上,将shell命令传输到目标端主机上运行并返回运行结果。
注意:两个主机需要网络可互通才行,例如源和端可以实现scp传输文件或者ping一下。
主机上ping一下IP看看网络是否能通信。
expect是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。
expect自动交互流程:
spawn启动指定进程—expect获取指定关键字—send向指定程序发送指定字符—执行完成退出.
expect常用命令
spawn 交互程序开始后面跟命令或者指定程序
expect 等待一个进程的反馈,if获取匹配信息匹配成功则执行expect后面的程序动作
send exp_send 用于发送指定的字符串信息
exp_continue 在expect中多次匹配就需要用到
send_user 用来打印输出相当于shell中的echo
exit 退出expect脚本
eof expect执行结束 退出
set 定义变量
puts 输出变量
set timeout 设置超时时间 :桥梁维持时间
interact 退出自动化,开始允许用户交互
自动登录脚本
自动远程登录脚本:bqh-nfs-123机器免输密登录bqh-back-124机器上
[root@bqh-nfs-123 scripts]# vim test.exp
#!/usr/bin/expect -f #expect的路径,which expect查询获取
set timeout 20 #连接超时
set host "192.168.0.124"
set password "123456"
spawn ssh root@$host #登录服务器用户+地址
expect { #等待接收进程返回的字符串
"yes/no" {send "yes\n";exp_continue} #等待输入yes
"password:" {send "$password\n"} #等待输入密码
}
interact #将脚本的控制权交给用户,用户可继续输入命令
注意:spawn命令中不识别通配符*
CURL(Linux发送Http请求)
大神总结-linux,curl命令发送各种请求详解
前提:
Linux主机和容器网络能通,所以可以通过linux主机访问容器。
主机上ping一下IP看看网络是否能通信。
简介:
curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是客户端(client)的 URL 工具的意思。它的功能非常强大,命令行参数多达几十种。如果熟练的话,完全可以取代 Postman 这一类的图形界面工具。
当你经常面对api时,curl将是你重要学习的工具,因为curl可以让你不需要浏览器也能作为Http客户端发送请求。而且它是跨平台的,Linux、Windows、Mac都会执行的很好。
例子:
curl -s -X POST http://IP:port/userInfo?userId=${参数变量} >> sysncinfo.log
-s, --silent Silent模式。不输出任务内容
-X, --request COMMAND 使用指定的post/get请求命令
BUG集合
Shell脚本首行规定
shell脚本若需要用到#!则必须放在首行,若首行是空格则在不同版本下会有问题。
一般情况:第一行的内容指定了shell脚本解释器的路径,而且这个指定路径只能放在文件的第一行。第一行写错或者不写时,系统会有一个默认的解释器进行解释。
每个脚本开头都使用"#!",#!实际上是一个2字节魔法数字,这是指定一个文件类型的特殊标记,在这种情况下,指的就是一个可执行的脚本。在#!之后,接一个路径名,这个路径名指定了一个解释脚本命令的程序,这个程序可以是shell,程序语言或者任意一个通用程序。
mkdir: cannot create directory ‘**’: No such file or directory
报错的原因是: mkdir创建多级目录时需要加参数 p。
mkdir -p /A/B:
- 正常情况下:若有A目录则在A目录下新建B文件夹
- 需要加P情况:若没有A目录则新建/A/B目录以及B文件夹
Syntax error: “then” unexpected和 command not found
在if判断中[]这个符号有特殊要求。[]与代码之间要有空格隔开的。
if空格[空格condition空格]
then
语句1
语句2
...
fi
变量定义格式错误
注意:不要在变量定义时等号之间乱加空格并且赋值时,若值包含空格则需要用引号包起来。
正确格式:
定义变量,不需要加$符号,例如:
声明即定义
name1='yxc' # 单引号定义字符串
name2="yxc" # 双引号定义字符串
name3=yxc # 也可以不加引号,同样表示字符串
文件重定向不能新建目录只能新建文件
>是覆盖file中内容,>>是将内容从末尾追加到file中
单独使用> /file.filetype可以起到新建/清空文件的效果。
注意:>和>>只能新建文件但是不能新建目录。
nohup运行脚本出错
本地终端跑一跑看看报错信息。
或者查看nohup.out
ln: failed to create symbolic link ‘/usr/bin/java’: File exists(翻译过来的意思就是:创建符号链接失败,文件存在。)
解决:ln: failed to create symbolic link ‘/usr/bin/java’: File exists
Linux中的硬链接、软链接及其基本原理
实际上就是创建快捷方式。
软链接,以路径的形式存在。类似于Windows操作系统中的快捷方式。
ln命令会保持每一处链接文件的同步性,也就是说,不论你改动了哪一处,其它的文件都会发生相同的变化;
无论是软链接还是硬链接,文件都保持同步变化。
- hard link(同步更新但不同步删除)
只是某个目录下新建一条文件名连接到某inode号码的关联记录本身不占空间。类似与c++中的智能指针,只要存在一个指向这个文件的记录,文件就一直存在 - soft link(同步更新且同步删除)
类似于window下的快捷方式,占用空间,源文件被删除后无效
in在linux中的意思是“创建链接”,in命令用于为指定的文件在另一个位置建立同步的链接,语法为“ln 参数 源文件 目标文件”;默认情况下创建硬链接,当参数设置为“-s”时,对源文件创建软链接。
-s 命令的意思是增加符号链接,起到一个链接的作用。
ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同步的链接.当我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我们只要在某个固定的目录,放上该文件,然后在其它的目录下用ln命令链接(link)它就可以,不必重复的占用磁盘空间。
第一,ln命令会保持每一处链接文件的同步性,也就是说,不论你改动了哪一处,其它的文件都会发生相同的变化;第二,ln的链接又分软链接和硬链接两种,软链接就是ln –s 源文件目标文件,它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间,硬链接 ln 源文件 目标文件,没有参数-s,它会在你选定的位置上生成一个和源文件大小相同的文件,无论是软链接还是硬链接,文件都保持同步变化。
1.命令格式:
ln [参数][源文件或目录][目标文件或目录]
软链接:
ln -s [源文件或目录][目标文件或目录]
把 -s 命令修改成 -sf 命令;-f 命令的意思是强制执行,也就意味着如果不存在就执行创建,存在就执行覆盖掉。
脚本权限不够,执行拒绝(需要chmod赋权)
chmod:修改文件权限
- chmod +x xxx:给xxx添加可执行权限
- chmod -x xxx:去掉xxx的可执行权限
- chmod 777 xxx:将xxx的权限改成777(全可读写执行)
二进制形式赋权,三位=0~7,7表示赋予全部权限 - chmod 777 xxx -R:递归修改整个文件夹的权限
date函数获取上/下月日期错误
根本原因:每个月天数不一致,该函数直接取到上/下月本日期,若为31号月末可能跨两个月
获取上月月份错误展示:
答案应该是:202402
标准格式:
直接确定坐标月份为当月一号$(date +%Y%m)01,而不是$(date +%Y%m%d)。
# 获取下一个月份:注意该函数直接取到下月本日期,若为31号月末可能跨两个月
month=$(date -d "$(date +%Y%m)01 next month" +%Y%m)
# 获取下个月的第一天
next_month=$(date -d "$(date +%Y%m)01 next month" +%Y%m01)
# 获取上月yyyymm
lastMonth=$(date -d "$(date +%Y%m)01 -1 month" +%Y%m)