Linux基础教程: 6、 shell入门和文件io基本操作

我们现在开始讲一下shell的基本语法和一些常用的语句,然后在学一下linux如何使用C语言完成文件的读写操作:

1、变量定义

linux也常常使用脚本语言,也就是shell,具有变量的无特定类型的特点,我们可以不写数据类型就可以进行定义和赋值,他的语句具有镜像的特点,比如if需要以fi结尾,case 要以esac结尾;那我们来走进shell的世界探索一番脚本语言的语法:

shell定义变量也是和C语言一样需要遵循规则的,比如一些不可以用作变量名的字符:标点符号、纯数字、关键字;

变量名=值
$变量名

C语言里面如果我们想要引用变量的时候直接写变量名叫就可以了,但是在shell中我们必须要加上$才行;注意空格的问题,在shell中很多时候会出现空格,一定要记住不可以随便删除空格;这里变量赋值的时候千万不要多添加空格,不然的话会报错:

(img-HaJQg6Kl-1667266627026)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20221024184612671.png)]

C语言中有全局变量的定义,shell里面叫做环境变量,有三种定义形式,分别作用于当前线程,当前用户和多用户都可以使用的变量:

export name=变量值
#在~/.bashrc 的最后一行加上上面的语句
#在 /etc/profile 的最后一行加上上面的语句

在这里插入图片描述

我们可以使用vi编辑器打开对应的文档然后加上这一句就可以了,两个文档都是一样的操作;

在这里插入图片描述

如果我们想要给变量清空赋值的话也比较简单,直接运行:

扫描二维码关注公众号,回复: 14732451 查看本文章
unset 变量名

在这里插入图片描述

可以看到我们定义了一个变量叫做a,赋值为1,然后执行了一下unset之后就清空了;

数组的定义:

list=(1,2,3,4)

echo ${list[1]}

第一个就是数组的定义了,后面一个其实就是数组的引用,这里强调一下必须要加的大括号,因为$在不加大括号的情况下只会引用list,而忽略掉[1];注意这里数组元素之间使用逗号隔开;

我们还可以使用一些shell中的特殊含义的字符,他们也是shell命令:#(个数)、@(所有数量)、$$(当前线程id)
在这里插入图片描述
这里的意思就是打印array所有元素的数量;除了用在数组中,这里的特殊字符还可以使用在位置参数中,也就是我们执行一个脚本文件的时候在后面添加的参数列表:
在这里插入图片描述

bash 脚本文件 参数列表

注意我们填写参数列表的时候是使用空格隔开的不是逗号,和数组一样的,然后我们可以是文件里面可以使用$+数字的方式,来引用位置参数,要注意的是我们无法改变这个未知参数的数值;然后就可以使用@表示所有的参数,#表示参数个数:

echo "my name is : sy"
echo "the first subject is : $1"
echo "the seccond subject is : $2"
echo "the third subject is : $3"
echo "the forth subject is : $4"
echo "the all subject subject is : $@ " 
echo "the number of subject is : $#"

echo "input your performance of Math,Chinese,English,Linux: "
read -p "your Math performance is : " Math
read -p "your Chinese performance is : " Chinese
read -p "your English performance is : " English
read -p "your Linux performance is : " Linux


shift
echo "the all subject subject is : $@ $Math $Chinese $English $Linux "                                                                           

这里有一个shift命令,作用就是将所有的位置参数往左移除一个,注意,移出去了就是用不了了;

2、计算式

既然是学习编程肯定是需要学习如何使用shell语言进行计算:

(($变量1+$变量2))
let c=$变量1+$变量
expr c=$变量1+$变量

这是常见的三种进行计算的方式,可以看得出来,shell里面的计算可不是那么好做;反正变量的引用就需要使用$,计算时还需要加上let 或者是expr,这三种方式其实是等价的,效果一样;我就不过多演示了:
在这里插入图片描述

如果是要计算小数我们得需要另写式子:

在这里插入图片描述

echo "scale=保留多少位小数; 小数1*小数2"|bc
printf %.保留小数位数f `echo 小数1*小数2|bc`
result=$(echo "scale=保留多少位小数; 小数1*小数2"|bc)

当然这里也可以引用变量小数,只不过不要忘记加上 ;第二种其实就是 C 语言的形式,那种数据的格式化输出;如果我们是要计算出来结果然后赋值给某一个变量的话就需要使用 ;第二种其实就是C语言的形式,那种数据的格式化输出;如果我们是要计算出来结果然后赋值给某一个变量的话就需要使用 ;第二种其实就是C语言的形式,那种数据的格式化输出;如果我们是要计算出来结果然后赋值给某一个变量的话就需要使用()或者$[]的方式,在括号里面输入计算的表达式

3、判断语句

现在我们来看看shell中的if判断语句和一些判断条件如何使用:
在这里插入图片描述

if [ $a -lt $b ];then
        echo " a < b"
fi

注意这[]里面存放的是判断语句,而且空格不能错:

-gt 大于号
-ge 大于等于号
-lt 小于号
-le 小于等于号
-eq 返回值比较,相同就真
-nq 不同就真

str1=str2 字符串比较
str1!=str2 字符串反比
-n str    不为空就真
-z str	  为空就真

这里常用的比较命令,需要记一下;

转义运算符 \ :
有时候我们想要输出一些含有特殊含义的命令符号,比如$ , @ 等,不可以直接打印,所以就使用转移运算符就可以了:

在这里插入图片描述

我们还可以使用多分支的判断语句:

read -p "请输入文件或者文件夹名称:" file
if [ -d $file ];then
        echo -n "$file是一个文件夹"
elif [ -x $file ];then
        echo -n "$file是一个可执行文件"
else
        echo -n "$file是一个普通文件"
fi
echo

我们使用了文件的基本几个判断,-d后面加上文件名是判断是否是一个文件夹,-x是判断可执行文件;注意一个规律,在判断语句的后面一般需要接上then,不要忘记这里的分号,在有循环的语句后面习惯使用do-done来代替C语言里面的大括号;

4、read接受用户输入

和C语言的scanf的功能一样,等待用户的输入:

在这里插入图片描述

read -p "文字描述" 参数列表

按照这样的格式来写,要求我们输入的时候就是按照参数列表的个数和顺序来输入数据就行了,这里提醒一个,就是echo后面的-n的作用就是清除换行;

5、selecte、case、for、while、until语句的基本使用

shell中也是有很多有趣的语句,比如开关和循环语句,与C语言不一样的事shell习惯使用do和done来代替大括号:

echo "What do you want to study?"
select subject in "Adnroid" "Java" "C++" "IOS"
do
	echo "You have selected $subject"
	break
done
exit 0

select其实也是一个循环,只要我们不选择选项中的项就会一直要你选择,这里我们设置了四个选项,它的执行效果比较特殊:
在这里插入图片描述

他会把in后面的参数列表全部列出来,然后要求你去选择,选择之后打印一句话;

case语句其实就是开关语句,也是一种循环的:

echo -n "a:"
read a
echo -n "b:"
read b
echo -n "select(+ - * /):"
read var
case $var in
        "+")echo "a+b=$[ $a+$b ]";;
        "-")echo "a-b=$[ $a-$b ]";;
        "*")echo "a*b=$[ $a*$b ]";;
        "/")echo "a/b=$[ $a/$b ]";;
        *)echo "error";;
esac
exit 0

看起来case比较特殊,因为它不需要使用do,而是用的镜像结束符;就是in前面使用一个变量,然后in后面接上我们可能会选择的所有情况,以"")开头双分号结尾(;;);这个变量就是我们会输入的变量;

for语句大致的使用还是和C语言差不多的,只是我们将大括号换成了do:

array=("Math","Chinese","Englihs","Linux")
for item in $array
do
        echo $item
done

一般我们在shell需要使用in来遍历,设置一个遍历的变量,然后在do里面写打印语句或者是处理数据的代码,记得以done结尾;

while语句就需要一个条件来判断什么时候退出循环了,同样要使用到do:

count=0
read -p "请输入最大值:" number
while [ $count -le $number ]
do
	echo $count
	((count=count+1))
done

同样是在while的后面是用了一个方括号来进行判定,如果是判断语句出现问题的话就可能死循环了;然后使用do来表示循环的开始就可以了;

until其实就是while的对立面,它只有在括号里面是假的时候才会执行do里面的语句:

count=0
read -p "请输入最大值:" number
until [ $count -ge $number ]
do
	echo $count
	((count=count+1))
done

这样写就是当我们的count小于number的时候执行do里面的语句,大于number的时候就不会执行;

6、调试脚本

C语言程序可以使用gdb来调试,当然shell也是不例外的,但是shell的调试要简单很多,他就只有三个:

bash -n 脚本文件 #意思就是我们程序如果有错误就不会执行,只会打印错误信息,当然没错的话就执行
bash -v  脚本文件 #意思就是打印程序执行过了得代码
bash -x 脚本文件 #意思就是将执行的过程打印到窗口上,-v就好像打印源码,但是这个会答应每一个变量变化的过程

在这里插入图片描述

非常详细;

7、变量的定义和调用

shell的变量定义和调用都比较简单:

#编写函数
function fun(){
    
    
	local a=10
	b=11
	echo "本地变量:"$a
}

#调用函数
fun

注意这里的变量,我么a加了一个local修饰就表示有了作用域只可以在函数里面使用;

11、文件操作

linux中的文件操作是使用的几个系统函数来实现的,使用的是C语言,关键作用的是文件描述符,可以说操作文件描述符就是操作文件,之前我们了解过三个文件的标号,因为文件描述符也是一个类似的索引值,就是说已经有了0,1,2了,所以我们打开文件之后返回的文件描述符只能从3开始;

1、阅读手册,了解i/o函数

在我们学习函数的使用前,最好就是阅读手册,先从头文件,然后就是函数的参数,返回值,描述。

输入下面的命令查看第一个i/o函数,open

man 2 open

Linux的man很强大,该手册分成很多section,使用man时可以指定不同的section来浏览,各个section意义如下:
1 - commands
2 - system calls
3 - library calls
4 - special files
5 - file formats and convertions
6 - games for linux
7 - macro packages and conventions
8 - system management commands
9 - 其他
解释一下,
1是普通的命令
2是系统调用,如open,write之类的(通过这个,至少可以很方便的查到调用这个函数,需要加什么头文件)
3是库函数,如printf,fread
4是特殊文件,也就是/dev下的各种设备文件
5是指文件的格式,比如passwd, 就会说明这个文件中各个字段的含义
6是给游戏留的,由各个游戏自己定义
7是附件还有一些变量,比如向environ这种全局变量在这里就有说明
8是系统管理用的命令,这些命令只能由root使用,如ifconfig

在这里插入图片描述

然后可以看到这样的页面,其实就是进入了手册了,先展示出来的是头文件和下面的一些函数,我们要是用他们的话这下头文件是需要导入的,这里我们可以看到第一个函数open,他需要传一个pathname,也就是文件的路径,我们可以使用一个字符数组来传递,如果是当前路径的话我们直接写文件名就行了,第二个参数就是我们要对文件进行什么操作类了,在文档后面的话都有说明,就是有一点,英文的不好阅读,都是简单词汇,有点基础的应该没有问题,这里我们一般像这样写就行了:

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
int main()
{
    
    

        int fb1,fb2=0;
        char filename1[]="readtext.txt";
        int length=0;
        char buf[1024]={
    
    0};
        fb1=open(filename1,O_RDWR|O_CREAT,0644);
        if(fb1==-1)
        {
    
    
                perror("read open error");
        }


        char filename2[]="writetxt.txt";
        if(fb2==-1){
    
    
                perror("write open error");
        }
        fb2=open(filename2,O_RDWR|O_CREAT,0644);
        while((length=read(fb1,buf,sizeof(buf)))>0)
        {
    
    
                write(fb2,buf,length);

        }
        close(fb1);
        close(fb2);




        return 0;

}

这就是完成一个文件复制的代码,我们来分析一下里面函数的使用,如果想要详细了解的话可以按照我们的那个指令:

man 2 read 

man 2 write

自行查看;

1、open

int fb1=0;
fb1=open(filename1,O_RDWR|O_CREAT,0644);

这里的返回值就是一个文件描述符,是open函数的返回值,所以后面我们使用read/write操作i/o的时候都是操作这个文件描述符;

参数1是文件名,参数2是我们想要对文件的操作,这里使用的是O_RDWR(以读写方式打开)|O_CREAT(创建文件,存在文件会出错),这两者结合起来就是有文件是就以读写打开,没有文件是就创建,参数3是我们的文件权限,之前我们就说过类似的,其实文件的权限就是一个8进制的数,一个数分别对应421,可读可写可执行;一般我们会使用0644,644是对应的用户用户组和所有用户的权限;

2、read

char buf[1024]={0};
length=read(fb1,buf,sizeof(buf)

文件的读写是这样的流程:读取文件时先将数据存放在缓存中,也即是这里的buf,然后读取文件的时候再从buf中读取数据,写入到目标文件中;第一个是文件描述符,也就是open的返回值,对应的就是那个文件,第二个就是缓存区,对应的就是字符数组,第三个就是长度,我们读取的话一般读取缓存区长度就行;

3、write

 fb2=open(filename2,O_RDWR|O_CREAT,0644);
 write(fb2,buf,length);

写入文件,我们是从缓存区写入数据的,所以我们可以拿到我们存放了数据的数组buf,第一个参数同样是文件描述符,只不过是打开写入的目标文件,第二个是缓存区,第三个是长度,这里我们要以真实读取的的长度为准,所以我们拿了read的返回值,就是真实长度;

最后不要忘了关闭文件流:

        close(fb1);
        close(fb2);

这个程序的逻辑也很好理解,就是我们打开要写和要读的文件,然后利用while循环读取数据然后写入到目标文件就可以了,这里就是注意一个长度的使用;

猜你喜欢

转载自blog.csdn.net/aiwanchengxu/article/details/127627779
今日推荐