Linux c高级
阅读原文时间:2021年08月29日阅读:1

目录

统一声明:

博客转载 声 明 : 本博客部分内容来源于网络、书籍、及各类手册。

        内容宗旨为方便查询、总结备份、开源分享。

        部分转载内容均有注明出处,如有侵权请联系博客告知并删除,谢谢!

百度云盘提取码:统一提取码: ziyu

一、Linux

嵌入式:计算机应用为中心、软硬件可裁剪的系统。

  • Linux 多任务、分时 的一个操作系统

  • GNU GNU is Not Unix 它是一个组织;

  • GPL 是一种协议。

  • Linux本身指的是一个操作系统内核,只有内核是无法使用的。

  • 我们系统使用操作系统一个包含内核和一批有用的应用集合,这就叫Linux发行版。

    Ubuntu、Redhat就是Linux的不同的发行版。

  • Red Hat 服务器

  • unbutu 桌面性能好 “人道主义”。

  • debian

    -------------------------------------------- [0-3G] 0XC000 0000
    应用层
    app程序、shell命令、shell脚本、程序
    | |
    | |
    | |
    内核层---------------------------系统调用--- [3-4G] 0xffff ffff(代表4G) 1 0000 0000
    文件管理
    内存管理
    进程管理 --> 程序的一次执行过程
    硬件管理

    网络管理

    硬件层
    LED LCD CAMERA 鼠标 键盘

-------------    4G
    内核
-------------    3G
    栈区      自动开辟自动释放
-------------
    堆区      手动malloc
-------------

静态区/数据区    全局/静态

-------------
 字符串常量
-------------
    代码段
-------------    0


whoami    我是谁
ls
    -a
    -l
    -r  递归查询
    -i  inode 一个编号,一种节点
    -lh
pwd
cd
    cd dir_name
    cd  路径 绝对路径 相对路径
    cd ~ 返回目录
    cd
    cd .
    cd ..
    cd - 返回上一步
mkdir
    -p  递归创建
rm mkdir dir_name    删除空目录
rm -r dir_name
touch file_name
rm file_name
cp
    cp 路径 路径 复制文件
    cp -r
        -a  目录的复制
mv
    mv 路径 路径
exit    退出
echo    输出
su        切换用户
sudo     权限
clear     清屏  快捷键:Ctrl+L

1.7.1、dpkg:(离线安装)

rxvt        _1%3a2.6.4-14               _i386      .deb
|            |
|            |                            32
|            |
软件名     主版本号   修订版本号        体系结构   后缀

软件包安装:

  sudo dpkg -i 软件包全称

卸载:

   sudo dpkg -r 软件名

清除软件包的配置文件:

  sudo dpkg -p 软件名

列举软件的相关信息的清单:

  sudo dpkg -L 软件名

查询版本号:

  sudo dpkg -l 软件名

查询软件安装包的状态:

  sudo dpkg -s 软件名

强制安装:

  sudo dpkg -f 软件名

虚拟机自定义伸缩窗口大小

  虚拟机 --> 首选项 --> 显示;

  更新 vmare tools

    点击 虚拟机---> 更新(重装) VMware tools

    跳转到一个界面,界面上有VMwareTools-10.3.10-13959562.tar.gz 这个压缩包,

    把这个安装包解压在家目录 tar -xvf VMwareTools-10.3.10-13959562.tar.gz (一直按enter键直到结束)

    结束后生成一个目录--vmware_tools_distrib, cd 进去这个目录,再执行 ./vmare_install.pl 这个可执行文件就可以了;

1.7.2、把windows的文件复制到Ubuntu中

(1)、拖拽的方式:

  直接把文件拖到终端,在前面加上 mv 移动到某一个路径(mv '/tmp/VMwareDnD/VUayTT/char_arr.c' ./my.c)

  或者在widows上,鼠标右键点击复制,再转到ubuntu上的终端上点击 右键---> paste filenames 也会有一个路径,同样

  在前面加上 mv 移动到当前; ( mv '/tmp/VMwareDnD/VUayTT/char_arr.c' ./)

(2)、创建共享文件夹

  虚拟机 -> 设置 -> 选项 -> 共享文件夹 -> 总是启用 ->选择一个windows中的一个文件夹作为共享文件夹

  终端访问: cd /mnt/hgfs/myshare

  共享文件夹设置失败解决问题:属性,设置兼容性;虚拟机关键。

1.8.1、编辑 --> 网络编辑器 --> 更改设置 --> 桥接模式 -->选择对应网卡 -->

虚拟机 --> 设置 --> 桥接模式。

网络图标:    --> edit conections --> 自动 / 静态
                                                ip:192.168.9.123
                                                子网掩码:255.255.255.0
                                                网关: 192.168.9.1

相关命令:    ifconfig        查看当前ip地址
            ctrl+c          结束当前进程
            ping + ip地址     连接某个ip

1.8.2、apt 需要外网

软件源:

   /ect/apt/sources.list

下载的路径:

   /var/cache/apt/archives/

更新源:

   sudo apt-get update

下载一个软件:

   sudo apt install 软件名:

卸载:

   sudo apt-get remove 软件名

清空:

   sudo apt-get clean 软件名

下载源码:

   sudo apt-get source 软件名

1.9.1、压缩

针对的是文件
        实质:
            把文件里的tab/空格等压缩。
            压缩的时候,原文件就没有了,生成了压缩文件;
            解压的时候压缩文件也变成了原文件;

                                速率  大小
.gz:                            最慢  最小
    gzip  1.c  -->  1.c.gz
.bz2:                            次之  次之
    bzip2 1.c  -->  1.c.bgz2
.xz                                最快  最大
    xz 1.c     -->  1.c.xz

1.9.2、解压

gunzip 1.c.gz     --> 1.c
bunzip 1.c.bz2    --> 1.c
unxz 1.c.xz        --> 1.c

1.9.3、归档

归档:针对的是一个目录    “把一个目录变成一个文件”
归档的时候源文件依旧存在,生成一个新的归档文件。
释放的时候,压缩文件也存在。

tar    参数 归档的文件    目录
    c   创建归档
    v   显示过程
    f   后面接文件
    x   释放后归档的文件还在

    z:  压缩成gzip
    j:  压缩成bzip2
    J:  压缩成xz
    eg:压缩
        tar -cvf test.tar test  --> test.tar
        释放:
        tar -xvf test.tar -->   test

1.9.4、压缩的实质就是归档并压缩

压缩:
    tar -   vzcf day1.tar.tar.gz day1   -->     day1.tar.gz
解压:
    tar -   xzvf day1.tar.tar.gz 

万能解压:
    tar -xvf test.tar.* (* 代表各种格式的压缩包)。

1.10.1、vi 三种模式

新建文件 vi toch

(1)、命令行模式

复制:nyy
粘贴:p
剪切:ndd
撤销:u
返向撤销:Ctrl + r

查找:
    /string  向下查找n  向上查找N
    /^string 查找以string开头的字符串
去光标移到到结尾:    G
光标移到到开头:    g
调整格式:gg=G

(2)、插入模式

a     /   i   /   b

(3)、底行模式

w
q
wq
q!
wq!
x
:num    去到某一行
srtnumer:设置行号
vsp
替换:
    .当前
    $最后
    g所有
    %全文
    s/str1/sre2/g   替换

    范围:s/str1/sre2/g
    .,$ s/str1/sre2/g
    % s/str1/sre2/g
块复制:
    : 1,3 y     --> 复制 1~3行

1.10.2、查看文件

cat head tail     nore less(不要)
    cat 文件名     //查看文件
    cat -n 文件名  //连同行号一起查看

    head -n 文件名 //查看前n行
    head -5 文件名 //查看前5行

    tail -n 文件名 //查看后n行
    tail -1 文件名 //查看最后1行

1.10.3、> 重定向

cat 1.c > 2.c    //把1.c里面的内容放到2.c里面,相当于复制

diff    比较一个文件一不一样,若没有输出内容,文件内容就一样;

>>    追加
    cat 1.c >> 2.c  //把1.c里面的内容追加到2.c

| 管道:把前面的结果作为后面的输入。
“|”是管道命令操作符,简称管道符。
    利用Linux所提供的管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。
    连续使用管道意味着第一个命令的输出会作为 第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。

    练习:把一个文件的第5行输出到终端上。
        ①
        head -5 /etc/passwd > 1.c
        tail -l 1.c
        ②
        head -5 /etc/passwd | tail -l

1.10.4、grep 搜索

grep “string” 参数 文件
    参数:
        -n  行号
        -R  递归搜索
        -i  不区分大小写
        -w  精确查找,字符串前后如果有内容就查询不到;

grep "include" -n 4.linux_高阶进阶.c

find 路径 -name 文件名

cut -d : -f 1,2 filename
    /etc/passwd

        farsight: x  :1000:1000:ubuntu,,,: /home/farsight: /bin/bash
            用户名   密码  uid  gid       描述   主目录
    练习:
        查一下当前用户
            用户名:UID:GID
                head -34 /etc/passwd | tail -1 | cut -d : -f 1,3,4
        查一下当前用户行号
            cat /etc/passwd | grep "farsight" -n | cut -d : -f 1

ls -l

    -rw-rw-r--    1    farsight farsight 18672  6月 15 08:48 4.linux_高阶进阶.c
        权限   链接数    用户      组
-:
    文件的类型   bcd-lsp
rw-:用户的权限    u
rw-:组的权限    g
r--:其他权限    o
所有权限:        ugo 或者   a


ls -l 列出属性
drwxr-xr-x
一个10个字符。第一个字符表示文件类型,后面9个字符表示文件权限。
rwx:r(可读)、w(可写)、x(可执行)。
第一组:表示文件属主权限。
第二组:表示属主所在的组用户的权限。
第三组:表示其他用户的权限。


r:4    w:2 x:1     最高权限:777
r    可读  4
w   可写    2
x   可执行  1
-    无权限 0
有了这个编码规则,则drwxr-xr-x    编码后为755
三个为一组:           7  5  5

(1)修改权限:

第一种修改权限的方法        ***
要把    drwxr--r--  则对应的编码为744
修改命令:chmod 744 文件名


第二种修改权限的方法:
在原来的权限基础上修改,即增加或减少某权限。
三个组用户的编码依次为:属主u    属主所在的组g 其他用户o
如属主增加可执行权限    chmod u+x 文件名
其他用户增加可写权限    chmod o+w 文件名
属主所在组用户去掉可执行权限    chmod g+x 文件名

    chmod 777 2.c 赋最高权限
    ls -l 2.c
    -rwxrwxrwx 1 farsight farsight 431  6月 16 09:24 2.c
     chmod u-x 2.c
     ls -l 2.c
    -rw-rwxrwx 1 farsight farsight 431  6月 16 09:24 2.c
     chmod g-x 2.c
     ls -l 2.c
    -rw-rw-rwx 1 farsight farsight 431  6月 16 09:24 2.c
     chmod o-w-x 2.c
     ls -l 2.c
    -rw-rw-r-- 1 farsight farsight 431  6月 16 09:24 2.c

(2)修改用户:

chown
    sudo chown  用户名 文件  修改文件所属的用户
    sudo chown  用户名:组名  修改文件用户和组
chgrp
    sudo chgrp root 2.c         修改文件的组

1.14.1、软链接:相当于windows的快捷方式

创建软连接文件:ln -s 源文件名 符号连接文件名
reg:ln -s src.c linker.c     linker.c就是src.c的一个符号连接文件

ln -s 源文件 链接文件
    ln -s a.out app
结论:
    (1)app 相当于a.out 的快捷方式;
    (2)app 是一个链接文件, a.out 是普通文件;
    (3)a.out 的链接数不变;
    (4)把源文件删除或者移动到其他路径,链接文件就不可以用了;
    (5) 用绝对路径创建软链接,把链接文件移动到其他路径是可以用的;
    eg:
         ls -n  /home/farsight/210501/day1/day1/a.out  app

            ls -l app
            lrwxrwxrwx 1 farsight farsight 37  6月 16 14:05 app -> /home/farsight/210501/day1/day1/a.out

1.14.2、硬连接:对文件起别名

ln 源文件名 连接文件
硬连接实际上和源文件在硬盘中是同一个东西,效果类似于硬盘上的一个文件。

结论:
    (1)链接数变了
    (2)两个文件的iNode号是一样的
    (3)硬链接的文件可有移动1到其他路径下使用
    (4)硬链接文件是一个普通文件


* :    匹配所有字符
? :    匹配一个字符

[]:
    [字符1字符2]        匹配字符1和字符2中的任意一个字符,不能同时匹配两个字符;[1234] == [1,2,3,4]
        ls name[12].c
    [字符1 - 字符2]     匹配到从字符1 至 字符2 的所有字符
        ls name[A-F].c
            如果出问题,清除本地化设置
                export LC_ALL = C
                还原:
                    unset LC_ALL

{}:touch name{1,2,3,4,5}.c        同时创建多个文件;

程序的一次执行过程

ps

ps -aux

ps -aux | grep a.out 查询a.out这个进程

top 动态检测进程

kill 4797 //kill 进程号 --> 杀死一个进程

man -a         查询所有
man    1 ls    1.表示查询的是Linux命令
man    2 xx    2.表示查询的是Linux api   系统调用
man    3 xx    3.表示查询的是Linux库函数

1.18.1、添加用户

adduser    用户名
    /etc/skel   模板文件
    /etc/passwd 用户信息
    /etc/group  组的信息

1.18.2、切换用户

su 用户名
    新用户用不了sudo
        解决:
            sudo su root                //进入root用户
            chmod u+w /etc/sudoers      //修改可执行权限
            sudo vi /etc/sudoers        //进入权限为普通用户修改
                添加:
                    test ALL = (ALL:ALL) ALL    //添加普通用户
                chmod u-w /etc/sudoers  //把权限修改回来

1.18.3、删除用户

deluser 用户名

1.18.4、关机和重启

sudo shutdown -h now        立即关机
sudo shutdown -h 16:00        关机
init 0                        关机
sudo shutdown -r now        立即重启
sudo reboot                    重启

1.18.5、usermod

sudo usermod -aG farsight mytest  把mytest这个用户追加到farsight这个组里;
    用 id 用户名    可以看到效果: id  mytest

sudo usermod -c hello mytest 把mytest这个用户的第五个描述修改为hello;

sudo usermod -d /home/farsight mytest  把mytest 这个用户的家目录改为 /home/farsiht 

sudo usermod -g farsight mytest 把mytest这个用户的组改为 farsight
    id mytest
    uid=1003(mytest) gid=1000(farsight) groups=1000(farsight)
sudo usermod -l test1 mytest 把mytest这个用户名改为test1

    注意:不要在用户登录的时候修改信息。若果还是报错,把当前终端退出, (exit)

1.18.6、修改密码

sudo passwd user1    为名为user的用户设置密码

1.19.1、查看磁盘的相关信息

sudo fdisk -l

  /dev/sda: 系统盘 --> Disk /dev/sda: 21.5 GB, 21474836480 bytes

1.19.2、查看磁盘分区信息

df -h

1.19.3、将U盘挂载在Ubuntu上: USB/2.0 3.0

虚拟机 -> 可移动设备 -> flush disk

在家目录创建:mkdir ~/udisk

挂载: sudo mount /dev/sdb1 ~/udisk

就可以进入到udisk中访问u盘:

取消挂载:

   sudo umout /dev/sda1 ~/udisk

域名解析服务器:
8.8.8.8
114.114.114.114.114
自己的ip地址: 192.168.6.81

sudo vi /etc/network/interfaces 打开配置文件
         auto lo
         iface lo inet loopback

         auto    eth0
         iface   eth0    inet    dhcp  //两个字符串之间是tab键的距离

sudo /etc/init.d/networking restart  让配置文件生效

如果没有图标:
sudo vi /etc/NetworkManager/NetworkManager.conf 

      2 [main]
      3 plugins=ifupdown,keyfile
      4 dns=dnsmasq
      5
      6 no-auto-default=00:0C:29:A4:5E:47,00:0C:29:85:E8:39,00:0C:29:02:7A:D6,
      7
      8 [ifupdown]
      9 managed=true  //把false 改成 true


env        查看环境变量
查看单个环境变量:
    echo $PATH
        PATH    它是用来保存系统可执行程序路径的变量
                    /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/farsight/OpenWrt-SDK-ar71xx-for-linux-i686-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin:/home/farsight/gcc-4.6.4/bin
    echo $HOME 主目录

    如何使得a.out可以直接使用:
        ①只针对当前终端有效。
            export PATH=${PATH}:./
            export  导入环境变量
            PATH    环境变量
            =       赋值
            ${PATH}    引用环境变量path 里的内容
            :       起到分割的作用
            ./      把当前路径加上去
        ②在当前用户下生效
            vi .bashrc  打开
            在最后的位置添加:
                //export PATH=${PATH}:./
                //export PATH=${PATH}:./home/farsight  在主目录下生效
        ③在所有文件下省效
            PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/game
            s:/home/farsight/OpenWrt-SDK-ar71xx-for-linux-i686-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/
            toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin:/home/farsight"
            source  /etc/environment    //让过程更改的环境变量生效
            或者 sudo reboot  重启;

二、shell

把shell脚本放在一个文件中,那么这个文件就是shell脚本

sh

csh

ksh

bash --> ubuntu

2.3.1、后缀为.sh

eg:(1)在家目录创建一个目录 mydir
    (2)把 /etc/passwd 和 /etc/groff 复制到mydir
    (3)压缩并归档位mydir.tar.gz
eg:#!/bin/bash
    cd
    mkdir mydir
    cp /etc/passwd ./mydir
    cp -a /etc/groff ./mydir
    tar -cvzf mydir.tar.gz mydir

2.3.2、shell脚本为解释器语言,不需要编译

2.3.3、运行

(1)创建脚本 :vi demo.sh

在开头加上:#!/bin/bash

(2)修改权限:

chmod 777 demo.sh 修改为可执行的文件

(3)执行脚本

./demo.sh
bash demo.sh
source demo.sh
    三种运行方式的区别:
        (1)./执行的时候需要赋上可执行的权限,后两者可以直接执行;
        (2)./和bash在执行的时候会新开一个字终端,最后把结果直接返回给终端。
        (3)source 执行的时候在当前终端执行,一般用来让某个脚本生效;

2.4.1、变量的定义

没有数据类型,不需要提前定义直接使用;

给变量赋值的时候等号左右不能有空格

每一行语句不需要加‘;’

变量名见名知意;

赋值给变量都默认为字符串;

2.4.2、变量的引用

$var

$(var)

2.4.3、在给吧变量赋值的时候可以加双引号和单引号,也可以不加:

单引号和双引号的区别:
    单引号和双引号内都可以加空格;
    单引号里面不能引用变量
给变量赋值的时候不需要加上 $
var=10
var=11; // 再次赋值

eg:#!/bin/bash
    a=22
    b="open book"
    c="$a open"

    echo $a
    echo $b
    echo $c
输出:
    22
    open book
    22 open

单行注释:    #
多行注释:    :<<EOF
                被注释的内容
            EOF
            或者
            :<<!
                被注释的内容
            !

2.4.4、删除变量:变量被删除后不能再次使用

unset var1
eg:myur1="www.baidu.com"
    unset myur1
    echo $myur1
输出:
            //空格

2.4.5、命令置换

把命令赋值给了一个变量
var=`ls`
或者
var=$(ls)        //不输出不会执行
eg:
    var=`ls`
    var1=$(ls)
    echo $var
    echo $var1

2.4.6、位置变量

$0    $1 $2 $3...
$#     $* $@     $$

$0    用./ 和 bash执行 代表shell脚本文件名,用source执行代表bash
$1    shell脚本文件名后面第一个参数
$2    shell脚本文件后面第二个参数

$*    和   $@ 表示shell文件名后面的所有参数,不包含文件名
$#    表示shell文件名后面所有的参数,不包含文件名
$$    表示进程号


练习:
    用一个变量1保存PATH, 变量2保存HOME, ----> 交换;
    var1=${PATH}
    var2=${HOME}
    echo var1: $var1
    echo var2: $var2
    var3=$var1
    var1=$var2
    var2=$var3
    echo var1: $var1
    echo var2: $var2

2.4.7、shell处理字符串

(1)、字符串的复制

str=hello
strl=$str
eg:#!/bin/bash
    str=hello
    str1=$str

    echo $str
    echo $str1
输出:    hello
        hello

(2)、字符串的连接

str=hello
str2="$str hello"
eg:#!/bin/bash
    str=hello
    str1=$str
    str2="$str1 hello"
    echo $str
    echo $str1
    echo $str2
输出:    hello
        hello
        hello hello

(3)、字符串的长度

string=“hdsjf”
echo $(#string)

(4)、字符串的提取

    strstr()      str1[] = "hello world"  str2[]= "world"

① ${str:start:len}
        从左边的0开始数,数到start的位置,从这个位置输出len个字符;
        eg:str="www.baidu.com"
            echo ${str:3:4}
                结果:
                    .bai
② ${str:start}
    从左边的0开始数,数到start的位置,从这个位置开始输出直到最后一个字符结束;
        eg:str="www.baidu.com"
            echo ${str:3}
            结果:
                .baidu.com
③ ${str:0-start:len}
    从右边的0开始数,数到start的位置,从这个位置的后一个字符开始输出len个字符;
        eg:str="www.baidu.com"
            echo ${str:0-4:3}
            结果:
                .co
④ ${str:0-start}
    从右边的0开始数,数到start的位置,从这个位置的后一个字符输出直到最后一个字符结束;
        eg:str="www.baidu.com"
            echo ${str:0-7}
                结果:
                idu.com

⑤ ${str#*sub} 从左边开始数,第一遇到 sub , 输出它后面的所有内容;
        eg: str="www.baidu.com www.baidu.com www.baidu.com" 针对于:⑤-⑧
            echo ${str#*bai}
            结果:du.com www.baidu.com www.baidu.com

⑥ ${str##*sub} 从左边开始数,最后一次遇到 sub , 输出它后面的所有内容;
        eg:str="www.baidu.com www.baidu.com www.baidu.com"
            echo ${str##*bai}
             结果
                du.com
⑦${str%sub*}  从右边开始数,第一次遇到 sub ,输出它前面的所有内容;
~                                  eg:str="www.baidu.com www.baidu.com www.baidu.com"
            echo ${str%bai*}
                结果:
                    www.baidu.com www.baidu.com www.

⑧${str%%sub*}   从右边开始数, 最后一次遇到 sub ,输出它前面的所有内容;
        eg:str="www.baidu.com www.baidu.com www.baidu.com"
            echo ${str%%bai*}
                结果:
                    www.

数组定义:

arr=(1 2 3 4)依次对数组赋值;数组的下标也从0开始数的。

arr=([0]=aaa [2]=bbb) 对数组里面的部分元素

注意:没有被赋值到的地方就为空(不是零)。

2.5.1、数组的引用:数组的下标也是从0开始数的

${数组名字[下标]}

2.5.2、引用整个数组

${arr[*]} 或者 ${arr[@]}

2.5.3、求数组元素的长度

echo ${#arr1[0]} //arr1[0]整个数组的长度

2.5.4、求整个数组里面被赋值的元素的个数

echo ${#arr1[@]}

2.5.5、清空数组

unset arr[0] 清空这个元素

unset arr[*] 清空整个数组

2.5.6、arr=(${arr[*]} "how are you") 在数组后面添加内容

arr=("hello" ${arr[*]}) 在数组前加内容

eg:
    #!/bin/bash
    arr=(1 2 3 4)
    echo ${arr[0]}
    echo ${arr[2]}
    echo ${arr[*]}
    echo ${arr[@]}
    arr[2]=20;
    arr[5]=10
    echo ${arr[5]}
    echo ---------------
    arr1=([0]=hello [3]=56 [6]=bbb)
    echo arr1:${arr1[0]}
    echo arr3:${arr1[3]}
    echo arr6:${arr1[6]}
    echo arr2:${arr1[2]}

    echo ${#arr1[0]}
    echo ${#arr1[@]}

    unset arr1[0]
    echo ${arr1[0]}
    echo ................
    unset arr1[*]
    echo ${arr1[*]}

结果:    1
        3
        1 2 3 4
        1 2 3 4
        10
        ---------------
        arr1:hello
        arr3:56
        arr6:bbb
        arr2:
        5
        3

        ................

read 变量

2.6.1、如果输入两个变量

用法:read var1 var2
    var1 和 var2 的复制通过第一个空格来分割,
        //空格前面的内容赋值给var1,后面的所有内容赋值给var2

单次输入
eg:#!/bin/bash
    echo "please enter a var ->:"
    read var
    echo var:$var

两次输入:            // 两次输入即可输入带空格的字符串;
    read var1
    read var2

2.6.2、read -p "提示" var //输入提示性的东西

2.6.3、read -a arr (数组名) //输入一个数组

read -p "请输入一个数组" -a arr // read -a arr

echo ${arr[*]}

2.6.4、read -n num var

read -n 5 var //输入5个字符以后直接退出

2.6.5、read -t 秒钟 var //在规定的时间内输入,超时自动退出

2.6.6、read -s var //输入的没有回显

eg:
        read -p "请输入用户名" var1
        read -p "请输入密码" -s var2
        echo var1 = $var1
        echo var2 = $var2

结果:    请输入用户名farsight
        请输入密码
        var1 = farsight
        var2 = 1


echo $var
echo hello
echo "hello"
echo 'hello'
echo -n "hello world" 不换行


+    -   *   /   %
>    <
++    --
**    幂运算
+=    -=  *=  /=
&&    ||  !
>    <   ==  =(shell也可以用来做等于)
&    |   ~   ^

2.8.1、(( ))

((表达式))

((表达式1,表达式2,表达式3)) 执行最后一个表达式的结果

取值:$((表达式))

(1)表达式里面取变量的时候可以加$,也可以不加;
(2)可以运算结果赋值给一个变量
    ret=$((表达式))
(3)可以支持自加或者自减运算
    ((var1++))
    echo $var1
(4)运算的时候可以加空格
(5)$?    执行成功,返回上一次执行过程(上一次逻辑为真返回0,上一次逻辑为假返回1)
(6)支持整数运算,不支持字符串运用


eg:#/bin/bash
    var1=10
    var2=20
    var3=$((var1+var2))
    echo var1+var2 = $var3
    var3=$(($var1 + $var2))
    echo var1+var2 = $var3

    ret=$(($var1+$var2))
    echo ret = $ret

    ((var1++))
    echo var1=$var1

    ((mm=3**2))
    echo mm=$mm

    echo $((mm=3**2))

    #复杂运算
    echo $((var1 > var2))
    echo $((var1 < var2))
    echo $?    #返回上一次执行结果
    ((var2 > var1))
    echo $?        #shell 逻辑为真返回0,为假返回1

输出:    var1+var2 = 30
        var1+var2 = 30
        ret = 30
        var1=11
        mm=9
        9
        0
        1
        0
        0

2.8.2、$ [ ]

ret=$[表达式]

ret=$[表达式1,表达式2,表达式3,……]

(1)需要把执行结果赋值给一个变量
(2)可以支持自加,自加的时候不能加$
(3)在运算的时候变量也可以加$,也可以不加
(4)如果有多个表达式则执行右边的结果
(5)支持整数运算,不支持字符串运用


eg:#/bin/bash
    var1=10
    var2=20

    ret=$[var1++]
    ret=$[$var1+$var2]
    echo $ret
    echo $var1

    ret=$[1,2,3,3+4]
    echo $ret

    ret=$var
    echo $ret
    ret=$[var+1]
    echo $ret

    ret=$[var * 3]
    echo $ret
    ret=$[var / 3]
    echo $ret
输出:    31
        11
        7

        1
        0
        0

2.8.3、expr

(1)支持整数运算并且支持字符串的相关操作
(2)expr    可以直接输出结果
(3)expr 的运算需要加空格
(4)expr 的运算,变量的引用需要加$
(5)expr 在赋值的时候需要命令置换
    ①var=`expr $var1 + $var2`
    ②var=$(expr $var1 + $var2)
(6)expr    不支持自加
(7)expr 不支持幂运算
(8)expr 识别不了*,需要加\字符
    \*
    \>
    &lt;
    \(\) 不加默认为数组


eg:#/bin/bash
    var1=10
    var2=20

    expr var1+var2
    expr $var1+$var2
    expr $var1 + $var2

    var=`expr $var1 + $var2`
    echo $var
    var=$(expr $var1 + $var2)
    echo $var

    expr $var1++ #不支持自加
    expr ++$var1
    expr $var1

    expr mm=3**2
    echo $mm

    ret=$(expr $mm=3**2)
    echo ret =  $ret

    expr $var1 \* $var2

输出:    var1+var2
        10+20
        30
        30
        30
        10++
        ++10
        10
        mm=3**2
        ret = =3**2
        200

2.8.4、字符串操作

匹配字符串:

expr match $var "sub" //从开头匹配字符串,有多少个字符相同就返回多少的数

eg:str="hellowoed"
    #str="hell owoed"   #error  不能加空格
    expr match $str "hel"
    expr match $str he
    expr match $str "wor"
    expr match $str w
    expr length $str   #求字符串长度

输出:    3
        2
        0
        0
        9


if [条件]
then
        shell语句1
else
        shell语句2
fi

if [条件]
then
        shell语句1
elif [条件]
        shell语句2
then
        shell语句3
else
        shell语句4
fi

判断:
①[表达式]    --&gt;     表达的前后必须加空格\[\]前后也要加空格;
②test 前后加空格

2.9.1、数字大小判断

-eg     等于
-ne     不等于
-gt     大于
-ge     大于等于
-lt     小于
-le     小于等于

2.9.2、逻辑的判断

&&    -->     -a
||    -->     -o
!    -->     !
练习:输入一个成绩,
    [90-100] A
    [70-90) B
    [60-70) C
    [0-60] D
eg:#/bin/bash
    read -p "please enter a sore:>" num
    if test $num -gt 100 -o $num -lt 0
    then
        echo "error  ---> [0-100]"
        exit 1
    fi

    if test $num -ge 90 -a $num -le 100
    then
        echo A
    elif test $num -ge 70 -a $num -lt 90
    then
        echo B
    elif test $num -ge 60 -a $num -lt 70
    then
        echo C
    else
        echo D
    fi
        #bash if_score.sh
        #. if_score.sh # ./if_score.sh
        source if_score.sh  

exit num
num == 1 非正常退出
num == 0  正常退出

shell文件中:再次调用脚本
     #bash if_score.sh
     #. if_score.sh # ./if_score.sh
     source if_score.sh

2.9.3、字符串的判断

-n 判断字符串非空

-z 判断字符串为空

= 判断字符串相等

!= 判断字符串不等

> 比较字符串的大小

<

if test -n "$var1" -a -n "$var2"

1参数放前面

2变量的引用需要加" ",不然输入空的时候会报错。

练习:从终端输入两个字符串,判断是否为空,如果不为空则比较大小;
eg:#!/bin/bash
    read var1
    read var2

    if test -n $var1 -a -n $var2
    then
        if test $var1 \> $var2
        then
            echo "$var1 > $var2"
        else
            echo "$var1 < $var2"
        fi
    else
        echo "不空"
    fi

2.9.4、文件判断

bsp-lcd

-b 判断文件是否存在,并且判断是否为块设备文件

-s 判断文件是否存在,并且判断是否为套接字文件

-p 判断文件是否存在,并且判断是否为管道文件

-f 判断文件是否存在,并且判断是否为普通文件

-c 判断文件是否存在,并且判断是否为字符设备文件

-L 判断文件是否存在,并且判断是否为链接文件

-d 判断文件是否存在,并且判断是否为目录文件

-e 判断文件是否存在,

-s 判断文件是否存在,且判断文件是否为空,文件大小大于0,返回真值。

练习:输入一个文件名字。判断是普通文件还是目录文件
eg:#!/bin/bash
    file="/home/farsight/HuaQing_vision/qrs210501/2.linux_c高级/day4/"

    #read -p "请输入一个文件名:" file

    if [ -f $file ]
    then
        echo "普通文件"
    elif [ -d $file ]
    then
        echo "目录文件"
    else
        echo "文件不存在"
    fi

2.9.5、判断文件的权限

-w     判断写权限
-r  判断有没有读权限
-x  判断有没有执行权限

2.9.6、判断文件的时间戳

-nt 比较两个文件的时间戳更新

-ot 比较两个文件的时间戳更旧

练习:输入一个文件名,判断是否具有写权限,如果有,那么将helloworld写在这个文件里,如果没有添加权限再写进去;
eg:#!/bin/bash
read -p "请输入一个文件名" filename
if test -w $filename
then
     echo "helloworld" > $filename
else
    echo "没有写权限"
    chmod u+w $filename
    echo "helloworld" > $filename


练习:输入两个文件名,判断时戳
eg:#!/bin/bash
    read -p "enter file1>:" file1
    read -p "enter file2>:" file2

    if test -e $file1 -a -e $file2
    then
        if test $file1 -nt $file2
        then
            cat $file1 > $file2
        else
            cat $file2 > $file1
        fi
    else
        echo "文件不存在"
    fi

2.9.7、case 表达式 in

参数1
    shell 语句1
    ;;
参数2
    shell 语句2
    ;;
参数3
    shell 语句3
    ;;
参数4
    shell 语句4
    ;;
esac


eg:echo '输入 1 到 4 之间的数字:'
    echo '你输入的数字为:'
    read aNum
    case $aNum in
        1)  echo '你选择了 1'
        ;;
        2)  echo '你选择了 2'
        ;;
        3)  echo '你选择了 3'
        ;;
        4)  echo '你选择了 4'
        ;;
        *)  echo '你没有输入 1 到 4 之间的数字'
        ;;
    esac


*    --> 所有


练习:模拟一个软件的下载的过程
#!/bin/bash
read -p "enter num :" app
read -p "请选择命令[Y/N/Q]" cmd

case $cmd in
    Y|YES|yes|)
        echo "$app 正在下载....."
        ;;
    N|NO|no|)
        echo "取消下载 $app....."
        ;;
    Q|quit|q|)
        exit 0
esac


        do
            语句
        done

无限循环:    while true
            do
                echo "***"
            done


练习:写一个加法计算器, 输入一个值就一直累加,输入 exit 退出;
eg:#!/bin/bash
        while read -p "请输入一个整数或者输入q 退出:" num
        do
            if test $num = q
            then
                exit 0
            else
                ((sum+=$num))
                echo ret: $sum
            fi
        done


用法1:
    for((表达式1;表达式2;表达式3))
    do
            shell语句块


用法2:
    for var in 单词列表
    do
        shlle语句
    done

    单词列表:
        1)如果是散乱的列表,列表中用空格作为分割;
        2)顺序的列表: {start..end}
                    eg:
                        for var int {1..100}

函数的一般形式:

function 函数名()

{

}

(1)shell函数没有形式参数,没有返回值(也可以有)
(2)函数中的变量为全局变量
(3)将命令执行的结果作为作为单词列表
(4)for var in `ls`
                1.function 代表这是一个函数
(5)使用local 修饰是局部变量


函数的调用:
函数名
    函数名:argv[1]     argv[2] ...
    |
    |
    |
    $0         $1         $2


eg:#!/bin/bash
    function add(){
        sum=$((10+20))
    }
    add
    echo $sum

    function add1(){
        sum=$(($1+$2))
    }
    add1 50 60
    echo $sum

    function add2(){
        local sum=$(($1+$2))
        return $sum
    }
    add2 $1 $2
    echo $?

三、c高级

操作虚拟的内存

3.2.1、数据类型

(1)、基本数据类型

int float char short long double

(2)、用户自定义的数据类型

数组: 在内存中连续开辟相同数据类型的空间

结构体:描述一个对象,对象具有很多的属性 

        关键字: struct

        结构体的数据类型 == 关键字+结构体名

        结构体指针 (01struct.c)
        结构体数组 (02struct_arr.c)

        字节对齐:32位系统下,4字节对齐, 会画图

共用体:类似于结构体

        关键字: union
        特性1:共用体中每个成员都共用同一个内存起始地址,共用体占用的内存等于最大的成员占用的内存
        特性2:如果对新的成员赋值,会把原来的成员的值覆盖掉

(3)、指针类型

(1)基本用法
    & : 取出变量的地址
    * : 取出地址的值

    05pointer.c

(2)特点 : 指针是有粗细的

(3)数组指针(行指针)    07shuzu_zhizhen.c   

(4)指针数组  08zhizhen_shuzu.c

(5)二级指针 09erji_pointer.c

(6)不定类型的指针 : void *

        pthread_create();

3.2.2、程序员手动开辟内存空间

malloc free

#include <stdio.h>
#include <stdlib.h>        //malloc包含头文件
int main(void)
{
    // 需要一个1000个int类型元素的数组

    // 第一步:申请和绑定
    int *p = (int *)malloc(1000*sizeof(int));

    // 第二步:检验分配是否成功
    if (NULL == p)
    {
        printf("malloc error.\n");
        return -1;
    }

    // 第三步:使用申请到的内存
    //p = NULL;
    //p = &a;       // 如果在free之前给p另外赋值,那么malloc申请的那段内存就丢失掉了
                    // malloc后p和返回的内存相绑定,p是那段内存在当前进程的唯一联系人
                    // 如果p没有free之前就丢了,那么这段内存就永远丢了。丢了的概念就是
                    // 在操作系统的堆管理器中这段内存是当前进程拿着的,但是你也用不了
                    // 所以你想申请新的内存来替换使用,这就叫程序“吃内存”,学名叫内存泄漏
    //申请后使用
    *(p+0) = 1;
    *(p+1) = 2;
    printf("*(p+0) = %d.\n", *(p+0));
    printf("*(p+1) = %d.\n", *(p+1));   

    *(p+222) = 133;
    *(p+223) = 222; 

    // 第四步:释放
    free(p);
    p = NULL;       //释放之后p指针就没有指向了;p=NULL,防止野指针

    printf("*(p+222) = %d.\n", *(p+222));
    printf("*(p+223) = %d.\n", *(p+223));

    return 0;
}

3.3.1、函数形式

返回值 函数名(参数)

{

}

3.3.2、函数传参

值传递

地址传递

3.3.3、函数封装

main.c : 主函数, 函数调用

fun.c : 各种方法

fun.h : 函数声明、结构体

3.3.4、指针函数:返回值是一个地址的函数

3.3.5、函数指针:本质是一个指针,指向一个函数

vi指定复制:shift+鼠标选择

3.3.6、函数指针数组:本质上是一个数组,保存的是一个函数指针。

3.3.7、递归函数:自己调用自己。注意必须有终止条件。

3.3.8、回调函数:点餐, 服务员, 厨师

回调函数模型

3.4.1、使用gcc对代码进行编译

  • 1>预处理 :

    gcc -E 1.c -o 1.i 预处理:用于将所有头文件以及宏定义替换成其真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多。

  • 2>编译 :

    gcc -S 1.c -o 1.s 生成汇编语言源代码文件

  • 3>汇编 :

    gcc -c 1.c -o 1.o 将上一步的汇编代码转换成机器码,二进制格式

  • 4>链接 :

    gcc 1.c 生成可执行文件,将多个目标文件以及所需要的库文件(.so等)链接成最终的可执行文件

3.4.1、使用gdb对代码进行调试

编译的时候需要添加一个-g的参数

gcc 08malloc.c -g

使用gdb运行程序

gdb a.out

获取帮助信息:

(gdb)help

查看代码

l 默认显示的是前10行

l 可以向下查看下面的10行

l - 向前显示10行

添加断点

b 行号

如何查看断点

info b

删除断点

delete 断点号

运行代码:

r 运行代码,在断点的位置会停掉

查看数据

p 变量

watch 变量

单步运行

n 单步运行,当遇到函数时不会显示函数执行过程

s 单步运行,当遇到函数时显示函数执行过程

继续运行

c 没有错误就继续向下运行,在断点的位置会停掉

退出调试:

q 退出

存储类型(6种) auto static register extern volatile const

3.5.1、auto: 在定义变量的时候,默认存储类型为auto。

全局变量和局部变量:

#include <stdio.h>

int x=10;
void func(void)
{
    printf("x = %d\n",x);
}

int main(int argc, const char *argv[])
{
    auto int x=5; //作用域 花括号
    printf("x = %d\n",x);  //5

    {
        auto int x=7;//作用域 花括号
        printf("x = %d\n",x); //7
    }   

    printf("x = %d\n",x); //5

    func(); //10

    return 0;
}

3.5.2、extern :可以用来声明变量或者函数是在其他文件中

#include <stdio.h>
extern int a, b;
extern int fun(int , int );    

int main()
{
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("a+b = %d\n", fun(a,b));
}

#include <stdio.h>
int a = 12, b = 13;

#include <stdio.h>
int fun(int a, int b)
{
    return a+b;
}

3.5.3、static

(1)、延长变量的生命周期

#include <stdio.h>

void func(void)
{
    static int a=1;
    static int b;
    //如果a没有被static修饰,默认a在栈上存放,当函数被调用的使用分配栈空间,当函数调用完,栈就会被释放了。所有这里打印的a的值都是2;

    //如果加上了static修饰,并且static修饰的变量被赋值了,static修饰的变量在静态区种的.data存放着,在函数执行结束的时候,data段不会被释放,所以打印的结果是2 3 4

    //static修饰的变量如果没有被初始化,变量在.bss段存放着

    a++;
    printf("b = %d\n",b);
    printf("a = %d\n",a);
}

int main(int argc, const char *argv[])
{
    func();
    func();
    func();
    return 0;
}

(2)、限定作用域(对象可以是函数,也可以是变量)

static修饰的变量或者函数只能在当前文件中使用

3.5.4、const :只读的变量

const int a=10;

a=100; //错误的,const修饰的变量不允许修改

(1)、const修饰局部变量 --> 可以改变值 栈区

(2)、const修饰全局变量 --> 不能改变值 只读区

#include <stdio.h>

const int b=500; //只读区

int main(int argc, const char *argv[])
{
    const int a=10; //栈
    //a=100;  //错误的,const修饰的变量不允许修改

    int *p=(int *)&a;
    *p=100;

    printf("*p = %d,a = %d\n",*p,a);

    p=(int *)&b;
    *p=123;
    printf("*p = %d,b = %d\n",*p,b);

    return 0;
}

(3)、const修饰指针

#include <stdio.h>

int main(int argc, const char *argv[])
{
    int a=100;
    int b=234;

//第一种
    const int *p=&a;
    *p=50;  //p指向的地址中的内容不能修改
    p=&b;   //p指向的地址可以修改

//第二种
    int const *p=&a;
    *p=50;  //p指向的地址中的内容不能修改
    p=&b;   //p指向的地址可以修改

//第三种
    int *const p=&a;
    *p=50;  //p指向的地址中的内容可以修改
    p=&b;   //p指向的地址不能修改

//第四种
    const int *const p=&a;
    *p=50;  //p指向的地址中的内容不能修改
    p=&b;   //p指向的地址不能修改

    return 0;
}

3.5.5、register :(寄存器)

register int a;

定义的register类型的变量要比不加register的时候执行的速率要快。

问题1:寄存器类型的变量执行的速率快,能不能把所有的变量都定义成寄存器类型的变量?

答案:不能,在芯片内部寄存器是有个数限制的,比如在A53硬件平台上只有40个寄存器。

问题2:在定义变量的时候const和volatile能不能同时使用?

答案:可以的,只读的状态寄存器

3.5.6、volatile:(易变的)

volatile int a;

(1)、编译器优化 -O3

volatile int *a=&b; //防止编译器对代码进行优化

*a = 110;

*a = 120;

(2)、防止cpu值取数据从缓存(cache register)中取

volatile修饰的变量每次都从内存中取出

(3)、在开发过程中需要定义变量的时候需要加volatile

   1.在定义硬件地址的时候。(比如:状态寄存器)

   2.在中断处理函数中访问的非自动变量时,需要添加volatile

   3.多个线程访问的同一个变量

例如:向0x80000000地址中写入0x12345678值

   volatile unsigned int *p=(volatile unsigned int *)0x80000000

   *p=0x12345678;

四、makefile

一个文件,对项目进行管理

Makefile可以体现你是否具备大型项目的开发能力

是一个工程管理器,管理较多的文件

是一个可执行程序,通过读取Makefile内容,调用编译器进行编译工作

(本质工作还是GCC在做)

根据文件时间戳来编译文件(文件更新时间)

只编译修改后的文件,而不用全部编译,节省时间。

Makefile是make读入的唯一配置工具

all:  //---标签
    gcc -E test.c  -o test.i
    gcc test.c -Wall -o test  //--要做的事情,前面是一个tab键!
clean:  //---标签
    rm test.i test

    1.make默认执行all标签下内容
    2.make clean 会执行clean标签后的内容,删除文件

all: //---标签
    gcc -E test.c  -o test.i
    gcc test.c -Wall -o test
.PHONY:        //伪指令
clean:
    rm test.i test
伪目标:不生成目标文件的目标为伪目标
.PHONY:    的作用是将clean文件属性屏蔽掉,只单纯的任务就是一个伪目标

目标:依赖文件

   操作

out:main.o fun1.o fun2.o
    gcc main.o fun1.o fun2.o -o out
main.o:main.c
    gcc -c main.c -o main.o
fun1.o:fun1.c
    gcc -c fun1.c -o fun1.o
fun2.o:fun2.c
    gcc -c fun2.c -o fun2.o

节省繁复的操作,方便替换

类似shell脚本中的变量

CC=gcc

$(CC)

CC=arm-linux-gcc 

out:main.o fun1.o fun2.o
    $(CC) main.o fun1.o fun2.o -o out
main.o:main.c
    $(CC) -c main.c -o main.o
fun1.o:fun1.c
    $(CC) -c fun1.c -o fun1.o
fun2.o:fun2.c
    $(CC) -c fun2.c -o fun2.o

    CC      默认值gcc CC = arm-linux-gcc
    RM      默认值为rm 删除命令
    CFLAGS  编译器的参数选项
    LDFLAGS 编译器链接文件及路径
    APP     文件最后生成的可执行程序a.out
    SRCS    所有的.c文件
    OBJS    依赖文件

    eg:
#编译时的编译选项
CFLAGS = -Wall -o2 -g -std=gnu99 -pthread -I./include -DMYDBG
LDFLAGS = -L./lib/x86/ -lcam -L./lib/x86/ -lserial -L./lib/x86/ -ltcp -ljpeg -lpthread 

#用户自定义变量,保存 可执行程序的名字
APP = server

#自定义变量,用来保存某个目录下的所有 C文件
SRCS     = $(wildcard ./src/*.c)

#自定义变量,将某个变量中的所有C文件,替换成 .o 文件
OBJS     = $(patsubst %.c, %.o,$(SRCS))

CC = gcc
#CC = arm-linux-gcc
all: $(APP)

$(APP): $(OBJS)
    $(CC) -o $(APP) $^ $(LDFLAGS)
    $(RM) $(OBJS)

clean:
    $(RM) $(OBJS) $(APP)

更多详情makefile 可参考文档 跟我一起学makefile 百度云下载链接:https://pan.baidu.com/s/1McHYZuCSGjpOK19UOqLQeQ

跳转:上一篇、Linux c基础!

待更新。。。

跳转:下一篇、数据结构与算法!

跳转:下一篇、数据结构与算法!

跳转:开头

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章