文章目录
- 一、概念
- linux内存
- 嵌入式
- 嵌入式层次图
- 判断小端和大端
- 二、linux系统操作命令
- ls查看
- cd 命令
- pwd命令
- touch 创建文件
- mkdir 创建目录
- chmod 修改权限
- man命令
- cp 拷贝
- mv 移动
- rm命令
- cat命令
- echo 命令
- tty命令->查看当前终端号
- clear 命令
- ldd命令 ->查看文件依赖哪些库
- printenv命令->打印环境变量
- eog命令 + 图片名-> 显示图片
- 权限掩码 umask命令
- 修改权限掩码
- 安装软件命令
- 离线安装命令dpkg
- 在线安装apt-get
- 在ubuntu中阅读代码的工具ctags
- 压缩和打包
- 1. 压缩:对象是文件
- 2.打包(归档):对象是目录
- 文件操作的命令
- 文件的查看
- cat命令
- head命令
- tail命令 ->tail -f +文件名 实时显示文件更新
- more命令
- less命令
- 查看二进制文件
- 文件中内容搜索的命令 grep
- 文件搜索命令 find
- 文件中内容截取cut(以行为单位处理)
- 通配符
- “*” 可以匹配任意长度的字符
- ? 只去匹配一个字符
- [字符1字符2...字符n]
- [起始字符-结束字符]
- [^ 字符1字符2...字符n]
- 文件权限的修改
- 修改用户的权限chmod
- 修改文件所属的用户chown
- 修改文件所属组的命令chgrp
- 链接
- 软链接 ln -s
- 硬链接 ln
- 用户管理命令
- 添加用户 adduser (添加组addgroup)
- 新添加用户没有sudo权限解决方法
- 关机或重启命令
- 用户切换命令 su 用户名 (输入当前用户的密码即可)
- 退出用户 exit
- 修改密码的命令 sudo passwd 用户名
- 用户信息修改命令usermod
- 问题:修改完用户信息后,新用户通过图形界面登录不进去?
- 查看用户信息的命令 id 用户名
- 删除用户deluser (删除组delgroup)
- 磁盘操作相关命令
- 查看ubuntu系统的磁盘 sudo fdisk -l
- 查看磁盘使用量信息的命令 sudo df -h
- 查看磁盘挂载相关的命令 sudo mount
- 对硬盘操作相关的命令
- 指定磁盘类型的命令
- 环境变量问题
- 添加只对当前终端生效的环境变量
- 添加只对当前用户生效的环境变量
- 添加对所有用户生效的环境变量
- 网络相关命令
- ip
- ip组成
- ip表示方式
- ip的种类
- .ipv4的网段划分
- 子网掩码
- 网关
- DNS 域名解析器
- 查看网络的命令 ifconfig
- 图像界面设置静态IP
- vim使用
- 修改自动补全的文件
- vim分为三种工作模式
- 1.命令行工作模式
- 复制 y
- 剪切 d
- gg直接跳到首行
- G直接跳到尾行
- 粘贴 p
- 撤销 u
- 反向撤销 ctrl + r
- 代码对齐
- 搜索及高亮显示
- 插入模式
- 底行模式
- 保存/退出文件
- 水平打开多个文件 vsp 文件名
- 垂直打开多个文件 sp 文件名
- 拷贝、剪切
- :n 跳转到第n行
- vi test.c +100 打开文件的时候直接跳转到100行
- :set nonu 取消行号
- :set nu 显示行号
- .:nohl 取消高亮显示
- 替换
- 三 、shell编程
- shell定义
- 什么是shell脚本
- 执行shell脚本
- ./脚本名 (chmod 0777 脚本名.sh)
- bash 脚本名
- source 脚本名
- 三者的区别
- shell中变量
- 变量引用
- 变量赋值
- shell中的注释
- 清除变量 unset
- 位置变量
- 变量的作用域local
- 只读变量 readonly
- 给变量赋值命令(命令->linux操作命令)
- 例:
- 字符串相关操作
- 1.字符串长度
- 2.字符串拷贝
- 3.字符串的追加
- 4.字符串中子字符串的提取
- shell中的数组
- 数组成员重新赋值
- 数组成员的访问
- 数组中所有成员
- 数组的成员的个数
- 数组成员的追加
- shell中的输入与输出
- read输入
- read 变量名
- read 变量名1 变量2
- read -a 数组名
- read -n number 变量名
- read -p "描述字段" 变量名
- read -s 变量名
- read -t 5 变量名
- echo输出
- echo $变量名
- echo -n $变量名
- echo -e $变量名
- 运算符
- 算数运算符
- (())整数运算
- $[]整数运算
- expr整数运算
- expr字符串的操作
- let整数运算
- if语句
- 在if语句中判断数字的大小
- 逻辑运算符
- 1.对字符串的判断(在if语句中字符串需要加上"")
- 练习:
- 2.对文件的类型的判断bsp-lcd
- 练习
- 3.文件权限的判断
- 练习
- 4.判断文件的时间戳
- 5.判断文件的inode号是否相同
- case ... in 语句
- 练习1
- 练习2
- while循环
- 练习1
- 练习2
- until循环
- 练习1
- for循环
- c语言风格的for循环(算术运算)
- shell特有风格的for循环(文件)
- 省略in部分的for循环
- 练习
- select in 语句
- break和continue
- shell中的函数
- 函数的调用
- 函数的参数通过位置变量获取
- shell中函数返回值的问题?
- 练习1
- 练习2
- 练习3
- 练习4
一、概念
linux内存
嵌入式
嵌入式以计算机应用为中心,软硬件可裁剪的,对功耗,功能体积,可靠性等有要求的专用的计算机系统。
嵌入式层次图
user:(用户空间)
命令 shell脚本 APP(glibc)
-----------------------------
命令行解析器
| [0-3G]
---------------系统调用-----------------------------
kernel:(内核层)
5大功能 | [3-4G]
1.进程管理 //有进程的创建、销毁与调用
2.内存管理 //内存申请、释放
3.文件管理
4.网络管理
5.设备管理 //设备驱动管理
hardware: (硬件层)
led camera sensor lcd sound
linux系统:分时多任务/多用户操作系统 linux系统一切皆文件
用户空间进入内核需要使用系统调用完成,系统 调用接口是内核已经给用户提供了。linux分为用户 空间和内核空间的原因是处于安全角度考虑。
判断小端和大端
在我们发送数据的时候,我们首先要确定是大端还是小端模式来进行的,在接收方接收的数据必须知道数据是大端还是小端模式,才能正确地读取和存储数据起来,否则就会出错
小端:ubuntu用的一般是小端
大端:数据通过网络字节区
代码区分:
#include <stdio.h>
union aa{ /* 使用共用体判断 */
unsigned char a;
unsigned int b;
};
int main(void)
{
union aa tt;
tt.b = 0x12345678;
if(tt.a == 0x78){
printf("小端\n");
}else if(tt.a == 0x12){
printf("大端\n");
}
return 0;
}
二、linux系统操作命令
ls查看
- ls -a // 显示隐藏文件
- ls -l // 列出文件属性
- ls -lh // 列举文件的时候将文件的属性信息一并显示,并把文件的大小按照单位显示
- ls -i // 显示文件的inode号,文件系统,唯一识别文件的一个序号
- ls -R // 递归显示所有文件,包括子目录文件
cd 命令
- cd ~ 或cd 回到家目录下
- cd - 回到上一次操作的目录下
- cd / 切换到根目录下
- cd . 切换到当前目录下
- cd …/ 切换到上一级目录下
pwd命令
显示当前的路径
touch 创建文件
touch 文件名
如果文件存在,更新文件的时间戳
如果文件不存在,创建文件
touch 文件1 文件2 文件3 …
同时创建多个文件
mkdir 创建目录
mkdir 目录名 //用来创建目录
mkdir -p 1/2/3 创建具备层级关系的目录
mkdir -m 0777 list 创建一个具备0777权限的目录
chmod 修改权限
chmod 权限 文件/目录
例:
chmod 0777 hello/
将hello目录的权限修改为0777
chmod 0441 2.c
将2.c的文件的权限修改为0441
man命令
man 1 ==>查看命令帮助手册
例 :
man 1 ls
man 2 ==>查看系统调用的帮助手册
例:
man 2 open ==>查看系统调用函数open
man 3 ==> 查看库函数的帮助手册
例:
man 3 fflush
man 7 ==> 查看网络相关的帮助手册
例:
man 7 ip
man 7 socket
cp 拷贝
cp 文件/目录 目录
将文件或者目录拷贝到某一个目录下
cp 绝对路径/文件名 目录名
cp 相对路径/文件名 目录名
将一个文件拷贝到目标目录下
拷贝目录需要加-r 或 -a
cp 绝对路径/目录名 目录名 -r 或 -a
cp 相对路径/目录名 目录名 -r 或 -a
将一个目录拷贝到目标目录下
cp ./COPYING ~/test.c
将COPYING文件拷贝到家目录下并重命名为test.c
cp ./net ~/1/2/3/aaa -r
拷贝目录的同时进行重命名
例:
1.在用户的家目录下,创建一个my-dir目录
cd
mkdir my-dir
2.将/etc下的passwd文件拷贝到my-dir目录下,并重命名为farsight.c
$ cp /etc/passwd ~/my-dir/farsight.c
3.将etc下的groff目录拷贝到my-dir下,并重命名为hello
cp /etc/groff/ ~/my-dir/hello -r
mv 移动
如果目标目录存在表示移动,如果不存在重命名
mv 文件/目录 目标目录下
mv 1.c ~
//将当前的1.c文件移动到/home/linux下
mv hello/ ~/1/2/3 (注意不需要加-r)
//将当前目录下的hello目录,移动到1/2/3目录下
重命名:
mv test.c farsight.c
将test.c重命名为farsight.c文件
mv net/ netnet/
将net目录重命名为netnet目录
例:
1.在用户的家目录下,创建一个my-dir1目录
cd
mkdir my-dir1
2.将/etc下的passwd文件拷贝到my-dir1目录下,并重命名为farsight.c (不使用cp重命名)
cp /etc/passwd ~/my-dir1/
mv passwd farsight.c
3.将etc下的groff目录拷贝到my-dir1下,并重命名为hello (不使用cp重命名)
cp /etc/groff/ ~/my-dir1/ -r
mv groff/ hello/
4.将my-dir1移动到共享目录下
mv ~/my-dir1 /mnt/hgfs/share
rm命令
rm 文件名 //删除文件
rm 目录名 -rf //删除目录 -r 递归删除
//-f 强制删除
rm *.c -f //强制删除所有的.c文件
例:
rm !(22.txt) //删除22.txt之外的所有的文件
cat命令
cat 命令用于查看文件内容,后跟文件名作为参数。
cat -n //显示每一行的行号
more命令一页一页显示文件内容,用法与cat一致
more在命令会在最后显示一个百分比,表示已显示内容占整个文件的比例。按空格键向下翻动一页,按Enter键向下滚动一行,按Q键退出
echo 命令
- echo “123123” 将字符串显示到终端上
- echo 123123 > 1.c //重定向,本来要在终端上显示的字符串,重定/向到1.c
- echo 123123 >> 1.c //>>追加,在文件的尾部新起一行,将字符串写入这一行
例:
在终端输入echo $? ==>可以查看int main函数的返回值
tty命令->查看当前终端号
clear 命令
清屏 或者 ctrl + l
ldd命令 ->查看文件依赖哪些库
ldd + 文件名
printenv命令->打印环境变量
eog命令 + 图片名-> 显示图片
权限掩码 umask命令
修改权限掩码
umask 0(把权限掩码去掉)
安装软件命令
linux软件包的管理
(1)rpm(redhat)
(2)deb(ubuntu)
在.deb这个软件包中包含可执行程序,
说明文档,man手册,配置文件等。
软件包的命名规则:
sl _ 3.03 - 16 _ i386 . deb
软件名 版本号 修订版本 架构 包的后缀
i386 :32位操作系统
amd64:64位操作系统
离线安装命令dpkg
在安装软件的时候,不会检查软件的依赖关系
安装软件:
sudo dpkg -i 软件包名
例:
sudo dpkg -i sl_3.03-16_i386.deb
查看安装软件的版本号
sudo dpkg -l 软件名
查看软件对应的各种信息安装的位置
sudo dpkg -L 软件名
软件的卸载(配置信息会保留)
sudo dpkg -r 软件名
完全卸载
sudo dpkg -P 软件名
在线安装apt-get
先检查软件的依赖,如果发现软件有依赖的其他软件,一并安装到自己的系统中
1.更新本地的源
sudo apt-get update
2.安装软件(/var/cache/apt/archives)
sudo apt-get install sl //安装小火车应用程序
sudo apt-get install oneko //安装一个小猫
sudo apt-get install bastet //俄罗斯方块
sudo apt-get install frozen-bubble //泡泡龙
sudo apt-get install kolourpaint4 //画图板
sudo apt-get install xawtv //打开摄像头的软件
sudo apt-get install -f sl //强制安装
3.卸载软件
sudo apt-get remove 软件名
4.获取软件的源码
sudo apt-get source 软件名
(获取软件对应源码)
例:
sudo apt-get source sl //下载sl的源码
tar -xvf sl_3.03.orig.tar.gz //解压
cd sl-3.03.orig //进入解压后的目录
vi sl.c //这个就是sl的源码
5.只下载不安装(下载到当前路径下)
sudo apt-get download 软件名
6.清除下载的软件包
sudo apt-get clean
仓库1 仓库2 … 仓库n
|------------------------|
|
服务器1 服务器2 … 服务器n
由于用户所在的位置不同,访问服务器的时候,速率也不同。
选择这个访问最快的服务器自己使用。
比如选择的服务器是163服务器。
选择163服务器的方法如下:
1.点击->search->Update Manager->settings->
输入密码1->ubuntu software->download from->
->http://mirrors.163.com/ubuntu
可以将上述的服务器1中的仓库的地址同步到ubuntu的本机上,
在本机上/etc/apt/source.list //源路径-如163服务器
每一个仓库中又有很多的软件包,在本机的这个目录
/var/lib/apt/lists/下记录的就是软件的链接位置。 //各个软件的地址
错误1:
如果提示错误在错误信息中看到/var/lib/apt/lists/内容
解决办法:
cd /var/lib/apt/lists/
sudo rm * -rf
错误2:
ubuntu没有联网?
联网的方法如下:
1.在vmware中找到“编辑”选项->虚拟网络编辑器->
更改设置->如果点进来没有看到vnet0 vnet1 vnet8
->点击还原默认配置(需要在关机情况下进行)
2.在上述还原默认配置之后,选择vnet0,桥接模式
在桥接模式先选择
1.自动
2.pcie :有线网卡
3.wireless:无线网卡选择完之后点击确认
3.虚拟机->设置->硬件->网络适配器->选择“桥接模式”
4.做完上述操作之后“开机”
5.在开机之后,在ubuntu窗口的右上角能看到上下箭头或者wifi图标的选项,点击->edit connections–>将看到的默认选项删除—>点击add添加一个联网的选项—>然后关闭即可。
6.测试是否能联通
ping www.baidu.com
PING www.a.shifen.com (182.61.200.7) 56(84) bytes of data.
64 bytes from 182.61.200.7: icmp_req=1 ttl=53 time=5.27 ms
在ubuntu中阅读代码的工具ctags
1.安装ctags工具
sudo apt-get install exuberant-ctags
2.创建索引
ctags -R ==>会生成一个tags的索引文件
执行make tags ==> 在内核中创建索引文件
3.查找
3.1在终端上查找
vi -t 想查找的对象
若vi -t 无法使用,可以在查看的内核源码处,执行make tags
3.2在文件内查找
ctrl+] 跳转到实现的位置
ctrl+t 返回
压缩和打包
1. 压缩:对象是文件
将文件可以压缩成如下格式的文件
.gz ---->gzip
.bz2 ---->bzip2
.xz ---->xz
上述三者的压缩率从上到下逐渐递增
上述三者的压缩速率从上到下逐渐递减
例:
gzip COPYING //将COPYING压缩成COPYING.gz
//压缩完之后源文件就不存在了
gunzip COPYING.gz //将.gz格式的压缩文件解压
bzip2 COPYING //将COPYING压缩成COPYING.bz2
//压缩完之后源文件就不存在了
bunzip2 COPYING.bz2 //将.bz2格式的压缩文件解压
xz COPYING //将COPYING压缩成COPYING.xz
//压缩完之后源文件就不存在了
unxz COPYING.xz //将.xz格式的压缩文件解压
2.打包(归档):对象是目录
tar 参数 对象
参数:
- -c :打包
- -x :解包
- -v :显示打包或者拆包的过程信息的
- -f :f可以理解为file,f后必须跟文件名
- -z :压缩成gzip格式
- -j :要压缩成bzip2格式
- -J :要压缩成xz格式
打包的命令如下:
tar -cvf 目录名.tar 目录名/
注意:c和v位置可以互换,但是f一定是在最后的位置的
拆包的命令如下:
tar -xvf 目录名.tar
就会生成以"目录名"命名的目录
例:有一个名为"work"的目录名
tar -czvf work.tar.gz work/ 打包并压缩
tar -xzvf work.tar.gz
tar -cjvf work.tar.bz2 work/
tar -xjvf work.tar.bz2
tar -cJvf work.tar.xz work/
tar -xJvf work.tar.xz
通用的解压命令
tar -xvf 名字.tar.bz2
目录在打包的时候,可以更换打包名字,但是解压出来名字还是原来的名字
文件操作的命令
文件的查看
vim 文件名(可以查看文件,也可以来编辑文件)
cat命令
cat -n 文件名
将文件的内容和行号显示到终端上
cat /etc/issue
用来查看ubuntu的版本号
head命令
head 文件名
默认显示文件中的前10行
head -20 文件名
显示文件的前20行的内容
head -3 文件名
显示文件的前3行的内容
tail命令 ->tail -f +文件名 实时显示文件更新
tail 文件名
显示文件的后10行
tail -20 文件名
显示文件的后20行
显示文件的13-16行
head -16 文件名 | tail -3
|(管道符):这个符号的功能是将前面的结果,作为下一个命令的输入。
例:
请将用户信息显示到终端上
用户信息存放在 /etc/passwd里面在第40行的位置
c: x:1000:1000:c,:/home/c:/bin/bash
c: \表示用户名
x: \表示有密码 -> 密码存放在 /etc/shadow 里面
1000:\ 表示用户的序列号
1000: \ 表示组的序列号
c \ 表示用户信息的描述字段
/home/c: \ 用户的主目录
/bin/bash \命令行解析器
使用:head -40 /etc/passwd | tail -1
more命令
more 文件名 //按照文件的本分比显示
按下回车往下显示
less命令
less 文件名
上键 向上显示
下键 向下显示
退出的时候使用q键
查看二进制文件
od -c 二进制文件名(例:a.out)
文件中内容搜索的命令 grep
grep “main”(要搜索的内容) * 参数
参数:
-n: 显示搜索到的行号
-R: 递归搜索
-i: 忽略大小写
-w: 精确搜索,只能知道main 对应的内容,main有前缀或后缀都检测不到
搜索以main开头的行:“^main”
搜索以main结尾的行:“main
”
"
m
a
i
n
” "^main
”"main":只有有main这一个单词
grep “main” * -nR //经常用的一种写法
例:
文件搜索命令 find
find 路径 -name 文件的名字
例:
find ./ -name test.c
搜索当前目录及子目录的所有的以test.c命名的文件
find …/…/ -name test.c
搜索上上级目录及子目录下的所有的以test.c命名的文件
find -name 文件名 (常用的写法)
搜索当前目录及子目录的所有的以test.c命名的文件
注意:
如果find命令在当期目录下所有搜索文件的时候,
不能模糊搜索(不能使用通配符号),必须精确搜索。
否则出现如下错误:find -name *.c
find: paths must precede expression: test.c
find -name * .c -exec grep -l “main” {} ;
// find -name *.c 搜索当前目录及子目录中的
所有的.c结尾的文件
//-exec grep:执行完find之后去执行grep命令
//-l :显示文件列表
//“main” :被搜索的字符串
//{} :它代表的是就是find -name *.c搜索
到的结果文件。
// ; :-exec执行的时候遇到;才会停止,
:但是由于;是一个特殊字符,必须使用
:转译才可以。
文件中内容截取cut(以行为单位处理)
cut(处理的时候是以行为单位)
-d :分割符号
-f :域
例:
test.txt
北京市:海淀区:育新花园:17号楼:304室
cut -d : -f 1 test.txt==>北京市
cut -d : -f 2,4 test.txt==>海淀区:17号楼
cut -d : -f 1,3-5 test.txt==>北京市:育新花园:17号楼:304室
北京市"海淀区"育新花园"17号楼"304室
cut -d " -f 2 test.txt ==>海淀区
例:
1.请将用户信息中的/etc/passwd
在终端上显示 用户名:uid:pid
结果:linux:1000:1000
命令:head -40 /etc/passwd | tail -1 | cut -d : -f 1,3-4
2.请将用户信息文件中,当前用户的行号显示出来
结果:40
命令:cat /etc/passwd | cut -d : -f 1 | grep “c” -nw | cut -d: -f 1
通配符
“*” 可以匹配任意长度的字符
例:
1.c 2.c 3.c 123123123.c sdfsfsdfsd.txt
ls * .c
显示当前目录下的所有的.c结尾的文件
? 只去匹配一个字符
例:
aa1.c aa2.c aaa.c aa12.c
ls aa?.c
结果是:aa1.c aa2.c aaa.c
[字符1字符2…字符n]
通配[]内部的任意的一个字符
例:
aa1.c aa2.c aaa.c aab.c
ls aa[1ab].c
结果:aa1.c aaa.c aab.c
[起始字符-结束字符]
通配起始字符到结束字符中的任意一个字符
例1:
aa1.c aa2.c aaa.c aab.c
执行:ls aa[1-9].c
结果:aa1.c aa2.c
执行:ls aa[a-z].c
结果:aaa.c aab.c
例2:
aaa.c aab.c aaA.c aaB.c
执行:ls aa[A-C].c
结果:aaA.c aab.c aaB.c
想得到的结果:aaA.c aaB.c
出现上述的原因是系统的语系问题,本地
的语系中字母的排序是
aAbBcC…zZ
解决办法:export LC_ALL=C
LC_ALL是系统中保存本地语系的一个变量
=C作用清除本地语系。
上述命令只在当前终端生效,换一个终端,
或者重启ubuntu就不生效了。
清除后的语系的排序:
abcd…z ABCD…Z
执行上述操作之后就可以得到正确的结果了
ls aa[A-C].c
结果:aaA.c aaB.c
[^ 字符1字符2…字符n]
通配除字符1 字符2 … 字符n之外的所有字符
例:
aa1.c aa2.c aaA.c aaB.c aaY.c aaa.c aab.c aay.c
执行:ls aa[^1y].c
结果:aa2.c aaA.c aaB.c aaY.c aaa.c aab.c
通配符 | 含义 |
---|---|
[:alnum:] | 代表英文大小写字母及数字 |
[:alpha:] | 代表英文大小写字母 |
[:blank:] | 代表空格和tab键 |
[:cntrl:] | 键盘上的控制按键,如CR,LF,TAB,DEL |
[:digit:] | 代表数字 |
[:graph:] | 代表空格符以外的其他 |
[:lower:] | 小写字母 |
[:print:] | 可以被打印出来的任何字符 |
[:upper:] | 代表大写字母 |
[:space:] | 任何会产生空白的字符如空格,tab,CR等 |
[:xdigit:] | 代表16进位的数字类型 |
文件权限的修改
d r-x r-x r-x 2 c c 4096 6月 18 17:09 dem01
r-x r-x r-x:权限
2:硬链接数
c : 用户
c : 组
修改用户的权限chmod
r-x r-x r-x
第一个表示:用户的权限 用 u 表示
第二个表示:组的权限 用g表示
第三个表示:其他用户的权限 用o表示
用+ :给权限
用- :去除权限
chmod u+w dem01 //给用户添加写的权限
chmod g-r dem01 //清除组读的权限
chmod uo+x aaA.c //将用户和其他人的可执行的权限添加上
chmod ugo+w aaA.c //将所有的写的权限添加上去
chmod a+w aaA.c //将所有的写的权限添加上去
a相当于ugo
修改文件所属的用户chown
chown 新用户名 文件
例:
将day2.txt文件所属的用户修改为root
sudo chown root day2.txt
将day2.txt文件所属的用户和组修改为root
sudo chown root:root day2.txt
将day2.txt文件所属的组修改为linux
sudo chown :linux day2.txt
修改文件所属组的命令chgrp
chgrp 新的组名 文件
例:
将day2.txt文件所属的组修改为root
sudo chgrp root day2.txt
链接
软链接 ln -s
软链接类似于windows的快捷方式
ln -s 被链接的文件 创建的链接文件
例:ln -s ~/exercise/dem01/num.c /home/c/1
软链接 可以链接文件或目录,两个都需要是绝对路径
建立软链接后,把软链接删除对原文件没影响
ln -f 强制创建链接文件,如果目标存在,那么先删除掉目标文件,然后再建立链接文件。
软链接特点:
①可以连接到目录
②可以跨文件系统
③删除源文件后,软链接文件也就打不开了
④符号连接文件通过->来指示具体的链接文件
⑤软链接需要创建给出绝对路径
拷贝 应使用 cp -d 命令,保持原文件类型不变
硬链接 ln
相当于是文件的别名
ln 被链接的文件 创建的链接文件
例:ln days my_days
建立硬链接后,两个文件是独立的文件,但是更改其中一个里面的内容后,另一个里面的内容也会更改
①具有相同inode的多个文件互为硬链接文件,创建硬链接相当于文件实体多了入口
②对于硬链接文件,只有删除了源文件以及对应的所有硬链接文件,文件实体才会被删除
③根据硬链接文件的特点,我们可以通过给文件创建硬链接的方式来防止文件误删除
④不论修改源文件还是链接文件,另一个文件的数据都会被改变
⑤硬链接不能跨文件系统 因为硬链接是根据inode号识别的
⑥硬链接不能连接目录
由于以上这些限制,硬链接不常用
用户管理命令
vi /etc/hostname ==> 修改主机名
vi /etc/hosts ==> 修改主机名
在172. … 里面把名字修改为主机名
在终端输入 hostname 可以查看
/etc/passwd =>用户信息的文件
/etc/group =>组信息的文件
/etc/shadow =>密码的文件
/etc/skel =>系统配置文件的模板目录
添加用户 adduser (添加组addgroup)
例:添加farsight 用户
sudo adduser farsight //添加fasight用户
添加时候显示如下信息:
Adding user farsight' ... Adding new group
farsight’ (1001) … =>组名及id号
Adding new user farsight' (1001) with group
farsight’ …=>用户名及id号
Creating home directory /home/farsight' ... Copying files from
/etc/skel’ … =>/etc/skel模板目录,里面是系统配置文件
Enter new UNIX password: =>密码2
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for farsight
Enter the new value, or press ENTER for the default
Full Name []: =>名字
Room Number []: =>地址
Work Phone []: =>电话
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
新添加用户没有sudo权限解决方法
执行sudo 出现如下错误:
farsight:is not in the sudoers file.This incident will be reported
解决办法:
首先切换到root 用户
su root
cd /etc/
chmod u+w sudoers //给sudoers这个文件的用户的写的权限添加上去
vi sudoers
找到 root ALL=(ALL:ALL) ALL
添加 farsight ALL=(ALL:ALL) ALL //表示给farsight用户sudo的权限
然后执行 chmod u-w sudoers //把添加的权限去掉
重启系统就生效了(16.04不用重启)
关机或重启命令
sudo shutdown -h +50 //50分钟后关机
sudo shutdown -h 10:30 //10:30关机
sudo shutdown -h now //立即关机
sudo poweroff //立即关机
sudo shutdown -r +50 //50分钟后重启
sudo shutdown -r 10:30 //10:30重启
sudo shutdown -r now //立即重启
sudo reboot //立即重启
用户切换命令 su 用户名 (输入当前用户的密码即可)
退出用户 exit
修改密码的命令 sudo passwd 用户名
用户信息修改命令usermod
切换用户,当前用户没有登录 //使用该命令,用户应处于没有登录状态
sudo usermod -aG linux farsight // 将farsight用户追加到linux组中
sudo usermod -c “hellohellohello” farsight //用来修改farsight用户/etc/passwd中描述字段信息,
//这里的,描述字段就是登陆时候显示的名字
sudo usermod -d /home/hello farsight // 用来修改用户的主目录,将farsight的主目录修改为/home/hello
sudo usermod -l hello farsight // 将farsight的用户名修改为hello
sudo usermod -g linux hello //将hello用户所属的组修改为linux(组名)
问题:修改完用户信息后,新用户通过图形界面登录不进去?
可以通过终端登录进入?
错误的原因是执行了如下命令:
sudo usermod -d /home/hello farsight
解决办法:
(fn)ctrl + alt +F1 ===>进入虚拟终端
1.将farsight目录下的内容拷贝到hello目录下
(注意这里需要将文件和hello目录的用户和组从root
用户修改当前用户和组即可)
2.sudo usermod -d /home/farsight hello
(fn)ctrl + alt +F7 ===>退出虚拟终端
查看用户信息的命令 id 用户名
删除用户deluser (删除组delgroup)
删除用户需要把用户关闭,在另一个用户进行
sudo deluser hello(要删除的用户) //删除用户,并将用户的主目录删除掉
磁盘操作相关命令
查看ubuntu系统的磁盘 sudo fdisk -l
查看磁盘使用量信息的命令 sudo df -h
/media/c/FAT32是U盘的目录
查看磁盘挂载相关的命令 sudo mount
一般为设备名(/dev/sdb1)目录名
对硬盘操作相关的命令
sudo fdisk /dev/sdb
Command (m for help): m
Command action
d 删除分区
l 列举分区
m 打印帮助菜单
n 添加新的分区
p 打印磁盘菜单
q 不保存退出
w 保存退出
指定磁盘类型的命令
sudo mkfs.ext4 /dev/sdb2 ===>ext4 日志文件系统 ubuntu
sudo mkfs.ntfs /dev/sdb2 ===>ntfs 单个文件可以超过4G
环境变量问题
保存系统启动相关,或者系统配置相关的变量。
在系统中可以通过env命令打印系统当前的环境变量
HOME=/home/linux #linux用户家目录
PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
添加只对当前终端生效的环境变量
export PATH=${PATH}:/home/c //使用绝对路径 并且只对当前层有效,进入下一层或上一层失效
添加只对当前用户生效的环境变量
.bashrc (在用户家目录下)
vi .bashrc
在最后添加
export PATH=${PATH}:/home/c
重启ubuntu生效
添加对所有用户生效的环境变量
sudo vi /etc/environment
在最后添加:
PATH=“/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/c/”
网络相关命令
ip
主机在网络中的一个编号,这个编号就是ip地址
ip组成
网络号+主机号 组成
ip表示方式
点分十进制
ip的种类
ipv4 (4字节,32bit) ipv6(16字节,128bit)
.ipv4的网段划分
等级 | 网络号 | 主机号 | 最高位 | 范围 | 使用单位 |
---|---|---|---|---|---|
A | 1字节 | 3字节 | 0 | [0-127] | 政府、大公司、学校 |
B | 2字节 | 2字节 | 10 | [128-191] | 中等规模公司 |
C | 3字节 | 1字节 | 110 | [192-233] | 个人 |
D | 1110 | [224-239] | 组播 | ||
E | 11110 | [240-255] | 未使用或(实验室) |
A : 0.0.0.0 - 127.255.255.255 //A网段地址范围
B: 128.0.0.0-191.255.255.255 //B网段地址范围
C:192.0.0.0-223.255.255.255 //C网段地址范围
D:224.0.0.0-239.255.255.255 //D网段地址范围
E:240.0.0.0-255.255.255.255 //E网段地址范围
子网掩码
例: 子网掩码:获取网络编号 192.168.1.160 & 255.255.255.0
得 : 192.168.1.0
网关
和外网通讯的ip地址,叫网关,一般咱们认为交换机的ip地址
DNS 域名解析器
www.baidu.com -->182.61.200.7
查看网络的命令 ifconfig
图像界面设置静态IP
address : 192.168.1.250
netmask : 255.255.255.0
gateway : 192.168.1.1
DNS : 8.8.8.8
重启网络管理服务
sudo service network-manager restart
测试:
ping www.baidu.com
PING www.a.shifen.com (182.61.200.7) 56(84) bytes of data.
64 bytes from 182.61.200.7: icmp_req=1 ttl=53 time=4.56 ms
使用命令配置网络
sudo vi /etc/network/interfaces
auto ens33
iface ens33 inet static
address 192.168.0.106 //ip 根据实际情况设定
netmask 255.255.255.0
gateway 192.168.0.1 //根据实际情况设定
broadcast 192.168.0.255 //根据实际情况设定
dns-nameservers 8.8.8.8
重启:
sudo /etc/init.d/networking restart 或 sudo systemctl restart NetworkManager.service
注意,上述重启之后需要修改配置文件,联网图标才能正常显示
在 /etc/NetworkManager/NetworkManager.conf. 中修改
ifupdown:managed=false ==>true //把false 修改为true
vim使用
先安装vim编辑器:
sudo apt-get install vim-gtk
修改自动补全的文件
linux@ubuntu:~/.vim/snippets$ vi c.snippets 路径
70 snippet main
71 #include <stdio.h>
72
73 int main(int argc, const char *argv[])
74 {
75 ±-- 2 lines: ${1}---------------------------------------------------------------------
77 }
~
vim分为三种工作模式
1.命令行工作模式
打开一个新的文件默认在命令行模式,或者按下键盘上的Esc键,也能回到命令行模式
复制 y
yy 复制光标所在的一行
3yy 复制光标所在的向下三行
nyy 复制光标所在的向下n行
使用鼠标选中想要拷贝的行,按下键盘的y
按下键盘的shift键,鼠标选中想要拷贝的行,
松开shift键,右键拷贝即可,然后在windows中粘贴。
如果是16.04之后的版本中,shift不松开即可。
剪切 d
dd 剪切光标所在的一行
3dd 剪切光标所在的向下三行
ndd 剪切光标所在的向下n行
使用鼠标选中想要剪切的行,按下键盘的d
dG 剪切光标所在到尾行的所有内容
dgg 剪切光标所在到首行的所有内容
gg直接跳到首行
G直接跳到尾行
粘贴 p
p 将缓冲区的内容粘贴,在光标的下一行粘贴
撤销 u
反向撤销 ctrl + r
代码对齐
gg=G
或者
鼠标选中想要 对齐的行,然后按下键盘的“=”
搜索及高亮显示
/^abc :高亮显示abc开头的行
/abc$ :高亮显示abc结尾的行
/^abc$ :高亮显示abc开头并结尾的行
插入模式
从命令行模式进入到插入模式
i :在光标前进入插入模式
I :在光标的行首进入插入模式
a :在光标后进入插入模式
A :在光标的行尾进入插入模式
o :在光标的行的下面新起一行进入插入模式
O :在光标的行的上面新起一行进入插入模式
底行模式
从命令行模式进入到底行模式shift + :
保存/退出文件
:w 保存
:q 退出
:q! 不保存退出
:wq 或x 保存退出
:wq! 强制保存退出
:wa 保存所有的文件
:qa! 不保存退出所有文件
:wqa 保存退出所有文件
水平打开多个文件 vsp 文件名
垂直打开多个文件 sp 文件名
拷贝、剪切
:7,8y 拷贝7-8行,通过命令行的p进行粘贴
:4,$y 拷贝4-尾行的内容
:1,7y 拷贝文件开头到第七行的内容
:7,8d 剪切7-8行,通过命令行的p进行粘贴
:4,$d 剪切4-尾行的内容
:1,7d 剪切文件开头到第七行的内容
:n 跳转到第n行
vi test.c +100 打开文件的时候直接跳转到100行
:set nonu 取消行号
:set nu 显示行号
.:nohl 取消高亮显示
替换
**:%s/旧字符串/新字符串/g**
例:
**:%s/abc/www/g**
//表示将文档中的所有的abc替换为www
**:%s/abc/www/**
//表示将文档中每行首次出现的abc替换为www
**:3,7s/abc/www/g**
//表示将3-7行所有的abc替换为www
**:3,7s/abc/www/**
//表示将3-7行首次出现的abc替换为www
**:4,$s/abc/www/g**
//表示将4到尾行所有的abc替换为www
**:4,$s/abc/www/**
//表示将4到尾行首次出现的abc替换为www
三 、shell编程
shell定义
(1)sh :(全称 Bourne Shell)是UNIX最初使用的 shell,
而且在每种 UNIX 上都可以使用。Bourne Shell 在 shell
编程方面相当优秀,但在处理与用户的交互方面做得不如
其他几种 shell。
(2)csh :是一种比 Bourne Shell更适合的变种 Shell,它的语法与 C 语言很相似
(3)ksh :集合了 C Shell 和 Bourne Shell 的优点并且和 Bourne Shell 完全兼容。
(4)bash :LinuxOS 默认的,它是 Bourne Shell 的扩展。
与 Bourne Shell 完全兼容,并且在 Bourne Shell 的基
础上增加了很多特性。可以提供命令补全,命令编辑和命
令历史等功能。它还包含了很多 C Shell 和 Korn Shell
中的优点,有灵活和强大的编辑接口,同时又很友好的用户界面
什么是shell脚本
它本身是一个以sh结尾的文件。在这个文件中就是命令的集合以及一些复杂的逻辑语句。
#!/bin/bash
作用:指定解析这个脚本文件的解析器是bash
执行shell脚本
./脚本名 (chmod 0777 脚本名.sh)
bash 脚本名
source 脚本名
三者的区别
-
./执行脚本的时候需要权限
bash/source执行脚本的时候不需要权限 -
./和bash在执行脚本的时候,系统会自动新开一个子终端,子终端我们看不到,在子终端执行完之后,将执行的结果返回给当前终端
source 解析脚本的时候是在当前终端解析的
shell中变量
在shell中变量不需要定义,也没有数据类型,直接使用即可
shell中的变量的变量名和c语言类似
1.不能和shell中的关键字重复 test if while echo cat
2.变量名一般写成大写的
3.变量名命名格式数字,字母,下划线,不能以数字作为开头
变量引用
$ 变量名 或者 ${变量名}
$() 错误的用法
变量赋值
变量再被赋值的时候,都是字符串,就没有整形,字符型,字符串类型,浮点类型之分
例:
VAR1= helloworld (一句话结束不需要向c一样加;)
VAR2='hello world
V
A
R
1
′
V
A
R
3
=
"
h
e
l
l
o
w
o
r
l
d
VAR1' VAR3="hello world
VAR1′VAR3="helloworldVAR1"
注意:
1.在赋值的时候=前后不允许有空格
2.如果在赋值的时候没有’'或"",赋值的字符串是不允许有空格的
3.’ '(单引号)在赋值的时候,可以有空格,但是不能够引用变量
4.“”(双引号)在赋值的时候,可以有空格,也能够引用变量,可以识别转译字符
shell中的注释
“#”单行注释
:<<EOF
被注释掉的多行
EOF
:<<!
被注释掉的多行
!
例:
#!/bin/bash
:<<EOF
这是注释部分
EOF
:<<!
这也是注释部分
!
# 这是单行注释部分
TMP=www.hqyj.com
VAR1=helloworld
VAR2='hello world\n$TMP'
VAR3="hello world\n$TMP"
echo -n ${VAR1}
echo $VAR2
echo -e $VAR3
echo ${VAR1}
清除变量 unset
unset 变量名 #(注意不能再变量前加$)
位置变量
参数 | 意义 |
---|---|
$0 | 显示脚本文件名 |
$1,$2,…$9 | 分别包含第一个到第九个命令行参数,后面还可以加$10,$11,但是写的时候,要用大括号{}扩起来 |
$# | 包含命令行参数的个数,这个值不包含文件名这个成员 |
$@ | 包含所有命令行参数:“$1,$2,…$9”,不包含文件名 |
$? | 1.程序上一步执行的结果,如果是0,表示执行成功了 如果是1,表示执行失败了。2.可以用来获取shell中函数的返回值 |
$* | 包含所有命令行参数:“$1,$2,…$9” ,不包含文件名 |
$$ | 包含正在执行进程的ID号 |
例: | |
如果在执行脚本的时候使用的是**./** |
**$0 => ./05var.sh**
如果在执行脚本的时候使用的是bash
$0 => 05var.sh
如果在执行脚本的时候使用的是source
$0 => bash
变量的作用域local
local 变量名
如果变量前不加local,默认的就是全局变量,如果添加了local只在{}内部有效
只读变量 readonly
readonly 变量名=“初值”
只读变量一定要赋初值,否则无意义。
给变量赋值命令(命令->linux操作命令)
VAR1=` ls ` (注意这不是单引号,是~对应的符号)
VAR2=$(ls)
注意上面:
或者$()这叫做命令置换
例:
#!/bin/bash
readonly HELLO="fsdddsds" #只读变量
echo $HELLO
HELLO="123" #HELLO是只读变量,在赋值会出错
echo $HELLO
Z=hello
echo $Z #Z的值为hello
unset Z #清除变量Z的值
echo $Z
VAR1=`ls` #使用ls命令
VAR2=$(ls) #使用ls命令
echo $VAR1
echo $VAR2
echo $0 #输出脚本名
echo $1 #输出终端输入的第一个值
echo $2 #输出终端输入的第二个值
echo $3 #输出终端输入的第三个值
echo "----------------------------------------"
echo $* #输出命令行参数,不包括脚本名
echo "----------------------------------------"
echo $@ #输出命令行参数,不包括脚本名
echo "----------------------------------------"
echo $# #输出命令行参数个数,不包括脚本名
字符串相关操作
1.字符串长度
echo $ {# STRING}
2.字符串拷贝
VAR1=“hello”
VAR2=“world”
VAR1=${VAR2}
3.字符串的追加
VAR1=“hello”
VAR2=“world”
VAR3=“$VAR1 $VAR2”
VAR3=“hello $VAR2”
VAR3=‘hello’’ world’
VAR3=‘hello’" world"
4.字符串中子字符串的提取
STRING=“w w w . h q y j . c o m”
echo ${STRING:4} 输出 #hqyj.com
#从第四个字符开始提取,提取到字符串的结尾
echo ${STRING:4:4} 输出 #hqyj
#从第四个字符开始提取,提取4个字符
STRING=“w w w . h q y j . c o m”
echo ${STRING:0-6} 输出 #yj.com
#从倒数第六个字符开始向后截取,截取到字符串的尾部
echo ${STRING:0-6:2} 输出 #yj
#从倒数第六个字符开始向后截取,截取向后的两个字符
STRING=“www.hqyj.com.hqyj.com”
echo ${STRING# yj}* 输出 #.com.hqyj.com
#获取yj首次出现的字符后的内容(从左向右)
echo ${STRING## yj}* 输出 #.com
#获取yj最后一次出现的字符后的内容(从左向右)
echo ${STRING%yj }* 输出 #www.hqyj.com.hq
#获取yj首次出现的字符前的内容(从右向左)
echo ${STRING%%yj }* 输出 #www.hq
#获取yj最后一次出现的字符前的内容(从右向左)
例:
#!/bin/bash
STRING="www.hqyj.com"
echo ${#STRING}
#获取字符串的长度
VAR1="hello"
VAR2="world"
VAR3="$VAR1 $VAR2"
VAR4='hello'' world'
echo $VAR3
echo $VAR4
#字符串的追加
#下面的都是字符串的提取方法
STRING="www.hqyj.com"
echo ${STRING:4} #hqyj.com
echo ${STRING:4:4} #hqyj
echo ${STRING:0-6} #yj.com
echo ${STRING:0-6:2} #yj
STRING="www.hqyj.com.hqyj.com"
echo ${STRING#*yj} #.com.hqyj.com
echo ${STRING##*yj} #.com
echo ${STRING%yj*} #www.hqyj.com.hq
echo ${STRING%%yj*} #www.hq
shell中的数组
shell中的数组只有一维数组,shell中的数组通过括号()代表。
shell中的数组也是不需要定义的,数组没有类型,全部认为是
字符串。
例:
arr=(11 22 33 “hello” “tt”)
arr=([0]=11 [2]=123123 [5]=“helloworld”)
数组成员重新赋值
数组名[下标]=新的值
数组成员的访问
${数组名[数组的下标]}
数组中所有成员
${数组名[@]} 或者 ${数组名[*]}
数组的成员的个数
${#数组名[@]} 或者 ${#数组名[*]}
数组成员的追加
arr=(${arr[@]} “rrr” “ttt”)
arr=(“rrr” “ttt” ${arr[@]})
例:
#!/bin/bash
arr=(
11
22
33
"hello"
"world"
)
#echo ${arr[0]}
#echo ${arr[1]}
#echo ${arr[2]}
#echo ${arr[3]}
#echo ${arr[4]}
echo ${arr[@]} #数组中成员的遍历
echo ${#arr[@]} #数组中成员的个数
#arr=(${arr[@]} "rrr" "ttt") #数组的追加
arr=("rrr" "ttt" ${arr[@]}) #数组的追加
echo ${arr[@]}
unset arr #清除整个数组中的成员
unset arr[0] #清除第0个成员
arr=(
[0]=123
[2]="hello"
[5]="ttt"
)
arr[1]="456" #对数组中的成员赋值
#echo "arr[0] = "${arr[0]}
#echo "arr[1] = "${arr[1]}
#echo "arr[2] = "${arr[2]}
echo ${arr[*]} #数组成员的遍历
echo ${#arr[*]} #数组中(被赋值)成员的个数
echo ${#arr[1]} #a[1]成员中字符的个数
shell中的输入与输出
read输入
read 变量名
#从终端读取一个字符串赋值给变量
read 变量名1 变量2
#从终端读取两个字符串赋值给两个变量,
#字符串和字符串间使用空格或Tab作为间隔
read -a 数组名
#输入一个数组,数组的成员以空格分开
read -n number 变量名
#从终端读取n个字符给变量,如果输入的字符的格式=number,会自动结束输入
read -p “描述字段” 变量名
#在让你输入字符串给变量前先将描述字段给显示一下
read -s 变量名
#在输入的时候取消回显
read -t 5 变量名
#在5s内如果没有输入,read就结束输入。
例:
echo -n "请输入一个变量"
read VAR1 VAR2
echo $VAR1
echo $VAR2
echo -n "请输入一个数组"
read -a ARR
echo ${ARR[@]}
echo ${#ARR[@]}
echo -n "请输入一个字符串"
read -n 5 VAR #字符串输入到5个后结束
echo
echo $VAR
read -n 5 -p "请输入一个整数> " VAR2
echo $VAR2
read -s -t 3 -p "密码 > " VAR2
echo $VAR2
read -t 10 -p "请输入一个有5个成员的数组" -a arr #10s内没有输入,自动结束输入
echo ${arr[@]}
echo输出
echo $变量名
#打印变量的内容并会加上换行
echo -n $变量名
#打印变量的内容,不会加上换行
echo -e $变量名
#打印变量的内容并会解析转译字符 \n
运算符
算数运算符
* / % **(幂) = == != + -
++ – && || ! > <
由于shell中没有指定数据的类型,所有的变量都当成字符串来处理。
所以要完成两个变量的运算,需要使用shell中算数运算符、算数指令
shell中对两个变量直接进行运算,会被当成字符串来处理
(())整数运算
$[] 整数运算
let 整数运算
expr整数运算,字符串相关操作
上述运算方式,指向效率(())—>expr依次递减的expr可以做字符串相关的操作,其他的是不行的。
(())整数运算
((表达式))
((表达式1,表达式2,…表达式n))
如果(())有多个表达式,最后一个表达式的结果
就是这个(())运算的结果
1.(())内部使用变量的时候,变量前可以加
也可以不加
也可以不加
也可以不加符号
2.如果想获取(())执行的结果,必须在前面加上$(())
3.(())可以做复杂的运算,比如for循环 ,判断大小
例:
#!/bin/bash
read -p "请输入两个整数 >" VAR1 VAR2 #比如输入55,12
echo $(($VAR1 + $VAR2)) #输出67
echo $((VAR1 + VAR2)) #输出67
echo $(($VAR1 + $VAR2,$VAR1 - $VAR2)) #输出最后一个表达式的结果为43
#!/bin/bash
read -p "请输入两个整数 >" VAR1 VAR2 #比如输入55,12
VAR3=$((VAR1++))
echo $VAR1 #56
echo $VAR3 #55
VAR4=$((++VAR1))
echo $VAR1 #57
echo $VAR4 #57
#!/bin/bash
read -p "请输入两个整数 >" VAR1 VAR2 #比如输入 2 3
VAR3=$((VAR1 * VAR2))
echo $VAR3 #6
VAR4=$((VAR1 ** VAR2))
echo $VAR4 #8
for((i=1;i<=100;i++)){
((sum+=i))
}
echo $sum #5050
RET=$((3,4,5,6))
echo $RET #6 输出最后一个数
a=6
b=5
VAL=$((a<b))
echo $VAL #a<b为假,返回0
$[]整数运算
ret=
[
表达式
]
r
e
t
=
[表达式] ret=
[表达式]ret=[表达式1,表达式2,…表达式n]
如果
[
]
有多个表达式,最后一个表达式的结果就是这个
[]有多个表达式,最后一个表达式的结果 就是这个
[]有多个表达式,最后一个表达式的结果就是这个[]运算的结果
1.$[]在执行运算的时候,必须有变量去承接它的结果
$[a+b] #运行错误
必须按如下写法:
echo
[
a
+
b
]
r
e
t
=
[a+b] ret=
[a+b]ret=[a+b]
2.在
[
]
内部调用变量的时候,变量前可以加
[]内部调用变量的时候,变量前可以加
[]内部调用变量的时候,变量前可以加也可以不加
∗
∗
∗
∗
3.
** **3.
∗∗∗∗3.[]不支持复杂的运算,比如for $[] 错误
例:
#!/bin/bash
a=5
b=6
ret=$[a + b]
echo $ret #11
echo $[$a + $b] #11
c=$[a++]
echo $c #5
echo $a #6
a=5
b=6
var1=$[$a<$b]
echo $var1 #1
expr整数运算
1.expr中运算的时候,变量必须使用 ∗ ∗ ∗ ∗ 2. e x p r 在运算的时候,运算符前后必须加空格 ∗ ∗ ∗ ∗ 3. e x p r 运算的结果会自动打印到终端上 ∗ ∗ ∗ ∗ 4. 将 e x p r 运算的结果赋值给某个变量的时候要使用命令置换 ‘ ‘ 或者 ** **2.expr在运算的时候,运算符前后必须加空格** **3.expr运算的结果会自动打印到终端上** **4.将expr运算的结果赋值给某个变量的时候要使用命令置换 ` ` 或者 ∗∗∗∗2.expr在运算的时候,运算符前后必须加空格∗∗∗∗3.expr运算的结果会自动打印到终端上∗∗∗∗4.将expr运算的结果赋值给某个变量的时候要使用命令置换‘‘或者()
5.expr做自加运算不行,可以替换成a=expr $a + 1
6.expr在运算*时候需要加上转译字符 ,不能运算等等**
例:
#!/bin/bash
a=5
b=6
echo `expr $a + $b` #输出11
expr $a + $b #输出11
a=`expr $a + 1`
echo $a #输出6
mul=`expr $a * $b`
echo $mul #输出36
expr字符串的操作
1.expr match 源字符串 子字符串
在源字符串中查找字符串差,如果源字符串中的
第一个字符和子字符串不相等结果为0,如果子字符串
有字符和源字符串中的字符不相等,返回的也是0.
否则返回的就是子字符串的长度。
例:
#!/bin/bash
string="www.hqyj.com"
expr match $string "www." #输出4
**2.expr substr $string 4 3 **
在string中截取从第四个字符开始,向后的3个字符
例:
#!/bin/bash
string="www.hqyj.com"
expr substr $string 4 3 #输出.hg
3.expr index $string “hj” #5
那h字符在string查找第一次出现的位置,如果
找到了就返回它前面的字符的个数,字符个数包括它本身,然后结束。
若找不到接着拿j字符在string查找第一次位置
如果找到返回j前面的字符个数,否则返回0
例:
#!/bin/bash
string="www.hqyj.com"
expr index $string "hj" #输出5
4.expr length $string
功能获取string变量字符串的长度
#!/bin/bash
string="www.hqyj.com"
expr length $string #输出12
let整数运算
let 表达式1 表达式2 … 表达式n
1.let会运算所有的表达式
2.let中变量可以加
,
也可以不加
,也可以不加
,也可以不加
3.运算符的前后不能加空格
例:
#!/bin/bash
a=5
b=6
let sum=$a+$b
echo $sum #11
let sum1=$a+$b sum2=$a+$b
echo $sum1 #11
echo $sum2 #11
let a=$a+1
echo $a #6
let mul=a*b
echo $mul #36
if语句
if 语句后面需要加空格 [ ] 里面的语句需要加空格与[ ]分开
♦ if …then …fi
语法结构:
if [ 表达式 ] ===>[ ] 用作判断的和test效果是一样
then ===>[ ] 替换为if test 表达式
分支语句
fi
● 如果表达式为真,则执行命令表中的命令;否则退出if 语句,即执行fi后面的语句
● if 和 fi 是条件语句的语句括号,必须成对使用
● 命令表中的命令可以是一条,也可以是若干条
如:
if [ 表达式 ]
then
分支语句
elif [ 表达式 ]
then
分支语句
else
分支语句
fi
在if语句中判断数字的大小
符号 | 判断 |
---|---|
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
-eq | 等于 |
-ne | 不等于 |
逻辑运算符
符号 | 判断 |
---|---|
-a | && |
-o | || |
! | ! |
例: | |
练习: |
90-100 A
80-89 B
70-79 C
60-69 D
<60 E
#!/bin/bash
read -p "请输入学生的成绩->" str1
if [ $str1 -ge 100 -o $str1 -le 0 ] # 大于100 或者小于0
then
echo "input error!"
exit 1 #直接返回
fi
if [ $str1 -ge 90 -a $str1 -le 100 ] #大于等于90 并且 小于等于100
then
echo "A"
elif [ $str1 -ge 80 -a $str1 -lt 90 ]
then
echo "B"
elif [ $str1 -ge 70 -a $str1 -lt 80 ]
then
echo "C"
elif [ $str1 -ge 60 -a $str1 -lt 70 ]
then
echo "D"
else
echo "E"
fi
练习:
90-100 A
80-89 B
70-79 C
60-69 D
<60 E
if [ $score -gt 100 -o $score -lt 0 ]
then
echo "input error"
exit 1
fi
if test $score -ge 90 -a $score -le 100
then
echo "A"
elif test $score -ge 80
then
echo "B"
elif test $score -ge 70
then
echo "C"
elif [ $score -ge 60 ]
then
echo "D"
else
echo "E"
fi
1.对字符串的判断(在if语句中字符串需要加上"")
符号 | 意义 |
---|---|
-z | 判断字符串是否为空 |
-n | 判断字符串是否为非空 |
=或者== | 判断两个字符串是否相等 |
!= | 不等于 |
\> | 判断字符串大小,大于 |
\< | 判断字符串大小,小于 |
练习:
输入两个字符串,判断字符串的大小,并输出
#!/bin/bash
read -p "please input str1 > " str1
read -p "please input str2 > " str2
if [ -z "$str1" -o -z "$str2" ]
then
echo "input string error,please try agian"
exit 1
fi
if [ "$str1" == "$str2" ]
then
echo "str1 = str2"
elif [ "$str1" \> "$str2" ]
then
echo "str1 > str2"
else
echo "str1 < str2"
fi
2.对文件的类型的判断bsp-lcd
-b 判断文件是否存在,并且判断文件是否是块设备
-c 判断文件是否存在,并且判断文件是否是字符设备
-d 判断文件是否存在,并且判断文件是否是目录
-f 判断文件是否存在,并且判断文件是否是普通文件
-L 判断文件是否存在,并且判断文件是否是链接文件
-S 判断文件是否存在,并且判断文件是否是套接字文件
-p 判断文件是否存在,并且判断文件是否是管道文件
-e 判断文件是否存在
如果文件存在,结果为真
如果文件存在,结果为假
(如果是链接文件,链接断开了,认为文件不存在)
-s 判断文件是否存在,并且判断文件是否为空
练习
请输入一个文件的名字,将它的类型输出
#!/bin/bash
read -p "请输入1个文件的名字" filename
if test -b $filename
then
echo "这是一个块设备文件"
elif test -c $filename
then
echo "这是一个字符设备文件"
elif test -d $filename
then
echo "这是一个目录"
elif test -f $filename
then
echo "这是一个普通文件"
elif test -L $filename
then
echo "这是一个链接文件"
elif test -S $filename
then
echo "这是一个套接字文件"
fi
3.文件权限的判断
-w 判断文件是否存在,并判断是否具备写的权限
-r 判断文件是否存在,并判断是否具备读的权限
-x 判断文件是否存在,并判断是否具备可执行的权限
练习
请输入一个文件,判断这个文件是否是普通文件,
如果文件是普通文件,判断文件是否具备写的权限,
如果文件具备写的权限,将"hello world"追加到文件尾部
#!/bin/bash
read -p "请输入1个文件的名字" filename
if test -f $filename #判断普通文件
then
if test -w $filename #判断是否具有写的权限
then
echo "hello world" >> $filename
echo "追加成功"
else
"文件不具备写的权限"
fi
else
if [ ! -e $filename ]
then
echo "文件不存在"
else
echo "输入的不是一个普通文件"
fi
fi
./dem1.sh #调用自己重新执行,文件名为dem1.sh
4.判断文件的时间戳
-nt 前面文件时间戳是否比后面文件的时间戳新
-ot 前面文件时间戳是否比后面文件的时间戳旧
5.判断文件的inode号是否相同
-ef 判断文件的inode是否相同
case … in 语句
case 变量 in
选项1)
分支1
;;
选项2)
分支2
;;
*)
分支n
;;
esac
练习1
1.在终端上输入一个字符,a-z A-Z打印这是一个字母
0-9这是一个数字, ,;“ ?这是一个标点符号
#!/bin/bash
read -p "输入一个字符" str1
case $str1 in
[0-9])
echo "这是一个数字"
;;
[a-zA-Z])
echo "这是一个字母"
;;
, |. | \" | \?) #? 是一个通配符,需要转义
echo "这是一个标点符号"
;;
*)
echo "非法输入"
;;
esac
练习2
输入软件的名字[Y/N/Q]?来决定是否下载,用户的选择可以是Y y YES Yes yes等都要满足
#!/bin/bash
read -p "请输入软件的名字" name
read -p "是否进行下载->(y|n|q)" down
case $down in
Y|y|YES|Yes|yes)
echo "下载软件"
;;
n|N|no|No)
echo "不下载软件"
;;
q|Q|Quit|QUIT)
exit 1 #程序退出
;;
esac
while循环
while 表达式
do
循环体
done
♦ while语句首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,直到该命令或表达式为假时退出循环
♦ while语句的退出状态为命令表中被执行的最后一条命令的退出状态
写 成while true 是死循环
练习1
时钟程序
#!/bin/bash
sec=58
min=02
hour=20
day=24
month=4
year=2020
function years() #函数
{
if ((year%100==0))
then
if ((year%400==0))
then
echo 1
else
echo 2
fi
elif ((year%4==0))
then
echo 1
else
echo 2
fi
}
while true
do
sleep 1
((sec++))
if [ $sec -ge 60 ]
then
sec=0;
((min++))
elif [ $min -ge 60 ]
then
min=0
((hour++))
elif [ $hour -ge 24 ]
then
hour=0
((day++))
case $month in
1|3|5|7|8|10|12)
if [ $day -ge 32 ]
then
day=1
((month++))
fi
;;
4|6|9|11)
if [ $day -ge 31 ]
then
day=1
((month++))
fi
;;
2)
ret=`years year`
if [ $ret -eq 1 ]
then
if [ $day -ge 30 ]
then
day=1
((month++))
fi
elif [ $ret -eq 2 ]
then
if [ $day -ge 29 ]
then
day=1
((month++))
fi
fi
;;
esac
if [ $month -ge 12 ]
then
month=1
((year++))
fi
fi
printf "%4d-%2d-%2d %02d:%02d:%02d\r" $year $month $day $hour $min $sec
done
练习2
求1-100的和
#!/bin/bash
i=1
while [ $i -le 100 ]
do
((sum+=i++))
done
echo $sum
until循环
until 表达式
do
循环体
done
until循环和while循环的功能类似,只不过until循环中的表达式要和while循环的表达式结果相反,此时until和while的功能就是一样的了
练习1
1.实现一个累加器(在终端上可以任意多的输入数据它会将输入数的和给求出来)
ctrl + c 相当于给程序发送了一个杀死进程的信号
ctrl + d 相当于发送了一个EOF,可以让read结束
#!/bin/bash
i=1
until [ $i -gt 100 ]
do
((sum+=i++))
done
echo $sum
for循环
c语言风格的for循环(算术运算)
for ((i=0;i<10;i++))
do
循环体
done
例:
#!/bin/bash
for ((i=1;i<=100;i++))
do
((sum+=i))
done
echo $sum
shell特有风格的for循环(文件)
for 变量 in 单词列表
do
循环体
done
1.单词列表的成员间是通过空格隔开
2.单词类别中可以使用命令的结果,命令需要加上命令置换符号 `` $()
3.如果单词列表是连续的成员{start…end}
seq 1 100
从1开始到100结束作为单词列表
seq 1 2 100
从1开始,中间跳过一个成员,到100结束
例:
#!/bin/bash
for i in `ls`
do
echo $i
done
省略in部分的for循环
for 变量 ==>省略in部分,会把命令行参数作为单词列表
do
循环体
done
#!/bin/bash
#1-100的和
for num in {1..100}
do
((sum+=$num))
done
echo $sum
#循环列表是a-z字符
for num in {a..z}
do
echo -n $num
done
printf "\n"
#1-100求和,跳过偶数部分
for num in $(seq 1 2 100)
do
echo $num
((sum+=$num))
done
echo $sum
#缺省in
for cmd_var
do
echo $cmd_var
done
练习
(1)判断用户主目录下是否存在file-dir和dir-dir的
子目录,如果存在则提示用户是否删除,如果用户输
入的是 yes,则删除,然后新建,否则结束 , 如果不
存在,则新建
(2)输入一个指定路径的目录,将这个目录下的文件和
目录分开存放,将文件拷贝到用户主目录下的
file-dir子目录下,将目录拷贝到用户主目录下
的dir-dir子目录下,并且统计文件和子目录的个数
(3)输出拷贝的文件和目录的个数
#!/bin/bash
user=("/home/c/file-dir/" "/home/c/dir-dir/")
for dir in ${user[@]}
do
if [ -d $dir ]
then
read -p "是否删除->$dir(y/n)" flase
case $flase in
y|Y|Yes|YES|yes)
echo "删除$dir目录"
rm $dir -rf
echo "新建$dir"
mkdir $dir
;;
n|N|NO|No|no)
echo "退出..."
exit 1
;;
*)
echo "选择无效..."
exit 1
esac
else
echo "新建目录"
mkdir $dir
fi
done
read -p "请输入一个路径> " mypath
if test -d $mypath
then
for file in `ls $mypath`
do
if test -f $mypath/$file
then
cp $mypath/$file ${user[0]}
((f++))
elif test -d $mypath/$file
then
cp $mypath/$file ${user[1]} -r
((d++))
fi
done
else
echo "输入的不是一个路径,请重试"
exit 1
fi
echo "拷贝的文件的个数$f"
echo "拷贝的文件的个数$d"
select in 语句
select 变量 in 单词列表
do
语句
done
#!/bin/bash
select ch in a b c d
do
echo $ch
break
done
#!/bin/bash
select sys in windows linux macOS ios Android
do
case $sys in
windows)
echo "welcome using windows"
;;
linux)
echo "welcome using linux"
;;
macOS)
echo "welcome using macOS"
;;
ios)
echo "welcome using ios"
;;
Android)
echo "welcome using Android"
;;
esac
break
done
#!/bin/bash
#PS3 它是系统的一个环境变量,默认值为#?
PS3="input >"
select ch in register login quit
do
case $ch in
register)
echo "注册"
;;
login)
echo "登录"
;;
quit)
echo "退出"
exit 1
;;
esac
done
select会生成一个选择的列表,如下
1) a
2) b
3) c
4) d
#? ==>可以输入用户的选择,这里只能
==>只能输入数字,不能输入单词列
==>表中的选项
select如果没有输入ctrl+d或者break它会一直
执行。
在工作或开发过程中select和case语句结合使用。
#PS3 它是系统的一个环境变量,默认值为#?
PS3=“input >”
break和continue
用法:
break ==>退出一层循环
break n ==>退出n层循环
用法:
continue ==>跳过一层循环
continue n ==>跳过n层循环
例:
输出:1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
#!/bin/bash
i=0
j=0
while ((++i))
do
j=0
while ((++j))
do
if [ $j -gt 4 ]
then
break
fi
if [ $i -gt 4 ]
then
break 2
fi
printf "%-4d" $((i*j))
done
printf "\n"
done
使用for循环实现
#!/bin/bash
j=1
for((i=1;i<=4;i++))
do
for((j=1;j*i<=4*i;j++))
do
printf "%d\t" $((j*i))
done
echo
done
shell中的函数
function 函数名()
{
}
1.shell中的函数没有参数列表
2.shell中的函数没有返回值类型
3.shell中的函数是使用function声明的
4.shell的函数名的命名和c语言一样
5.shell的函数如果不调用的话是不会执行的
函数的调用
函数名 参数列表1 参数列表2
函数的参数通过位置变量获取
$0 :脚本的名字
$1 $2 $3 …
$@
∗
"
* "
∗"@" 将命令行的参数原封不动的传递给子函数
“$*” 将命令行的参数看成一个整体传递给子函数
shell中函数返回值的问题?
1.shell函数的的变量默认都是全局变量,
可以直接使用,但是如果变量被local声明了
它就变成了局部变量。
2.shell中的函数执行的结果可以通过return返回,
return返回的时候可以通过$?获取返回的结果。
返回值的范围是[0-255]
3.shell的函数可以通过echo来返回字符串
通过ret=`` 或ret=$() 获取结果,注意在
函数中使用一次echo即可,如果在函数内
使用了多次echo,获取的结果就是多次echo的值
中间通过空格分开
#!/bin/bash
function ShowVar()
{
echo $0
echo $1
echo $2
echo "----------------"
echo $@
echo "#########################"
}
#ShowVar $@
#ShowVar "$@"
#ShowVar $*
#ShowVar "$*"
function Add()
{
((sum=$1+$2))
}
Add 12 23 #函数中的sum是全局变量
echo $sum #可以直接获取值
function Add1()
{
local sum
((sum=$1+$2))
return $sum
}
Add1 255 0 #函数中的local sum是局部变量,可以通过return返回【0-255】
echo $? #$?获取上一步调用函数的结果
function ShowEcho()
{
((sum=$1+$2))
echo $sum
}
ret=`ShowEcho 255 255` #若函数需要返回【0-255】区间外的数据或者返回字符串
echo $ret #在函数中调用echo就行了,在调用函数执行的时候需要加上命
#令置换,不能通过$?获取结果
#ret=`ls /home/linux/` #通过对本次赋值理解为什么函数中的
#echo $ret #echo没有输出
练习1
1.输入用户的名字,判断该系统上是否存在该用户
2.若存在该用户将这个用户名和uid和gid显示出来
#!/bin/bash
#打印行号
function check_user()
{
local line=`cat /etc/passwd | cut -d : -f 1 |grep "$1" -nw |cut -d : -f 1`
echo $line
}
#打印uid,pid
function show_user_info()
{
local info=`head -"$1" /etc/passwd | tail -1 | cut -d : -f 1,3-4`
echo $info
}
while true
do
read -p "请输入用户的名 > " name
if [ $name = quit ]
then
echo "退出用户查询系统"
exit 1
fi
line=`check_user $name`
if [ -z "$line" ]
then
echo "用户不存在"
continue
else
echo "用户存在,行号是$line"
fi
info=`show_user_info $line`
echo $info
done
练习2
封装一个对数组成员求和的函数,并将求得结果返回
#!/bin/bash
function array_sum()
{
local sum
for i
do
((sum+=$i))
done
echo $sum
}
arr=(11 22 33 44 55)
sum=`array_sum ${arr[@]}`
echo $sum
练习3
1.请输入一个路径,若此目录下文件是以.c结尾
的文件,并且是普通文件,请将这个文件编译,
若文件不是.c结尾的文件,请在文件结尾加上.bak
#!/bin/bash
read -p "输入一个路径" mypath
if test -d $mypath
then
for file in `ls $mypath`
do
if test -f $mypath/$file
then
case $mypath/$file in
*.c)
gcc $mypath/$file
mv a.out $mypath
;;
*)
base=${file%.*} #把原来的后缀清除
mv $mypath/$file $mypath/${base}.bak #添加新的后缀
;;
esac
fi
done
fi
练习4
1.编写一个shell脚本完成如下功能 :
1.在家目录下创建文件夹filer
2.遍历当前文件夹下的文件,如果是普通文件则放入创建的filer中
3.打印出放入filer文件夹中的文件数目
#!/bin/bash
cd
mkdir filer
for file in `ls `
do
if test -f $file
then
cp $file ./filer
((f++))
fi
done
echo "拷贝文件的个数$f"