基础概念

Linux系统内核指的是硬件抽象层、硬盘及文件系统控制及多任务功能的系统核心程序。 Linux操作系统是由Linux内核与各种常用软件的集合产品

shell:shell是系统的用户界面,他起到命令解释器的作用,能够把用户输入翻译成内核能够理解的内容

avatar

文件目录

avatar

bin -> usr/bin:普通用户使用的命令
sbin -> usr/sbin:管理员使用的命令
dev:设备文件(usb等连接到系统的任何设备)和特殊文件(块设备和字符设备等)
boot:引导加载程序文件
etc:配置文件
home:家目录,存放普通用户的个人档案
lib -> usr/lib:系统库,共享库文件以及内核模块文件
lib64 -> usr/lib64:专用于x86_64的辅助共享文件库
media:便携移动设备挂载点
mnt:临时文件系统挂载点
opt:第三方应用安装的地方
proc:输出内核与进程信息相关的虚拟文件系统
root:系统管理员的主目录
run:运行中进程相关的数据,存储进程的pid文件
srv:系统上运行的服务用到的数据,包含服务器特定服务相关的数据
tmp:临时文件存放位置,重启时清空
usr:二进制文件、库文件、文档、二级程序的源代码
var:存放着经常发生变化是数据文件

绝对位置、相对位置

常用命令

ip a 查看ip

ssh 用户名@ip

yum install 包名 安装软件包

hostnamectl set-hostname 主机名 修改主机名

systemctl disable firewalld 关闭防火墙开机自启

poweroff关机

pwd:查看当前所在目录

关闭selinux

setenforce 0
sed -i "s/=enforcing/=disabled/g" /etc/sysconfig/selinux

配置防火墙

firewall-cmd --permanent --add-service=ftp
firewall-cmd --reload 12

初始化

yum install -y bash-completion //自动补全
yum install -y vim
hoatnamectl set-hostname server1 //修改主机名
systemctl disable firewalld //关闭防火墙开机自启

//做完后记得拍快照

基础指令

echo 字符串:输出字符串

whoami:输出当前用户名

date:查看当前时间

ls:查看当前目录的文件:

-a:查看所有文件
-d:目录
-l:将文件的详细信息以长格式的形式展开,可以直接输入ll
-h:将文件的大小以人看得懂的单位显示
-t:按时间逆序排序
-r:文件名逆序,默认是顺序
-i:打印inode号

命令后面的参数有两种-短参数和--长参数,短参数可以多条合并

history:查看命令历史

-a:追加记录到.bash_history
-d id:删除历史中指定的命令
-c:清空历史命令
!id:执行对于命令
!$:执行上一个命令的最后一个参数,如果没有参数,就执行命令本身
!string:查找以string开头的命令
^R:搜索历史命令

.bash_history文件记录了所有的命令历史,但是不是同步更新

alias str='cmd':别名,临时生效

想要永久别名需要修改/etc/bashrc,alias str='cmd'

cd des:切换目录

pwd:显示当前目录

文件管理

mkdir [-] name:创建目录

-m:配置文件权限
-p:递归创建
-v:显示创建过程

mkdir -pv /home/file{a..d}#一次性创建多个文件

touch name:创建新文件,当文件/目录已存在时,会更改其时间属性

cp [] src des:拷贝文件和目录

-f:强制,如果目标文件依旧存在且无法开启,则删除后再来一次
-i:如果目标已存在,覆盖前先询问,默认cp=ci -i
-l:复制为硬链接
-s:复制为软连接
-d:如果目标是链接,想要复制连接而非复制原文件,则使用这个,只复制连接属性
-p:连同属性一起复制过去
-r:递归
-a:-pdr
-u:如果des比src旧才升级
-v:显示过程

src为单个文件:

    des不存在,则把src写入到des中
    des存在,覆盖

src存在,des是目录:创建并写入

src是多个文件
    des必须是目录,src为目录:-r

    des为目录:
    des不存在:创建
    des存在:写入,如果文件已存在则覆盖
    des为文件:报错


mv src des:移动,可以改名

rm [] file:删除


-r:递归
-f:强制
-v:详细过程

建议移动到对应文件夹使用!以防从入门到删库跑路!

cat:一次性加载所有内容,顺序

tac:同cat,但是逆序

less:不会一次性加载所有内容,空格翻页,回车加载一行,可以回看

more:和less类似,但是不可回看

head:查看文件开头部分


-n:指定行数

tail:从文件尾部读取,并且会监控文件的更新

-n:指定行数,``-n +10``表示从第十行到结尾
-f:循环读取,监视更新

grep 'str' file:对内容进行过滤

vi/vim

光标跳转

上下左右

上下左右
#command:跳转#个字符

单词跳转

w:下个单词的词首
e:下个单词的词尾
b:上个单词的词首
#command:跳转#个单词

行首行尾跳转

^:行首非空白字符
0:行首
$:行尾

行间移动

#G:跳到第#行
G:跳到尾巴
gg:跳到开头

文本编辑

删除

d:配合光标跳转删除
d^
d$
d#command
d0
dw
de
db
dd:删除光标所在行
#dd:删除多行
ggdG:删除全部

x删除光标所在字符
#x

复制剪切粘贴撤销

y,复制,用法类d
yy 以行为单位
#yy #行
ygg
yG

p粘贴

u撤销

模式转换

插入模式

a:选中字母后
i:选中字母
o:选中一行下面新建一行
A:行尾
esc:退出

末行模式

:
#:进入第几行
w:保存
w filename:另存为
q:退出
command!:强制
x 、ZZ:保存并退出
X:加密文档
r filename:读入文件到当前行后
# r filename:读入文件到5行后

查找替换

s/old/new/选项(g全文,c交互确认) 替换

50,100 s/man/MAN/gc 把50到100的man换成MAN并确认每一个替换

,$ s/.*// 从光标所在行开始一直到最后替换为空
如果出现替换文本里面有/,担心会造成歧义,可以使用#或者@来替代/

环境配置

在vim里面输入的都是临时的配置,如需永久环境,个人修改自己目录下的.vimrc,全局修改/etc/vimrc

set nu:行号
set nonu:取消行号
set ai:自动缩进
set noai:取消自动缩进
set ic:忽略字符的大小写
set noic:不忽略
set hlsearch:高亮搜索
set nohlsearch:不高亮
set sm:括号匹配
set nosm:不匹配
help:帮助

封装

将属性和方法封装到一个抽象的类种,外界使用类创建对象,调用其方法,具体内部的细节外部不需要知道

class Gun:
    def __init__(self,model):
        self.model = model
        self.bullet_count = 0
    def add_bullet(self,count):
        self.bullet_count += count
    def shoot(self):
        while True:
            if self.bullet_count == 0:
                print('没子弹啦!')
                break
            else:
                print('突')
                self.bullet_count -= 1

class Soldier:
    def __init__(self,name,gun=None):
        self.name = name
        self.gun = gun
    def fire(self):
        if self.gun == None:
            print("你没有枪呀!")
        else:
            self.gun.add_bullet(30)
            self.gun.shoot()

AK = Gun("AK47")
zhangsan = Soldier('张三',AK)
zhangsan.fire()

多态

不同的子类对象继承相同的父类,通过重写父类方法,产生不同的执行结果,增加代码的灵活性

class Phone:
    def __init__(self,name):
        self.name = name
    def func(self):
        print('bibibibi,来电话了')

class Nokia(Phone):
    def func(self):
        print("砸个核桃给秀儿吃")

class Samsung(Phone):
    def func(self):
        print("嘀嘀嘀嘀嘀嘀......Booooooooooom!")

class Person:
    def __init__(self,name):
        self.name = name

    def use_phone(self,phone):
        print(f'{self.name}正在使用{phone.name}')
        phone.func()

诺基亚 = Nokia('诺基亚')
三星Note7 = Samsung('三星Note7')

张三 = Person('张三')

张三.use_phone(诺基亚)
张三.use_phone(三星Note7)

我们可以对类进行约束来达到标准化的目的:

  1. 父类中定义方法,但是这个方法啥都不干,或者使用元类来描述一个抽象方法
  2. 子类中再具体实现方法
#抽象类写法
# import abc
# class Payment(metaclass=abc.ABCMeta):
#     @abc.abstractmethod
#     def pay(self,money):
#         raise AttributeError('子类必须实现这个方法')

class Payment:
    def pay(self,money):
        print('你还没有实现具体的pay方法')

class QQpay(Payment):
    def pay(self,money):
        print(f'QQ支付{money}元')

class Wechatpay(Payment):
    def pay(self,money):
        print(f'微信支付{money}元')

class Alipay(Payment):
    def pay(self,money):
        print(f'支付宝支付{money}元')

def pay(obj,money):
    obj.pay(money)

a = QQpay()
b = Wechatpay()
c = Alipay()
pay(a,200)
pay(b,200)
pay(c,200)

递归:在一个函数内再调用这个函数本身
递归的最大深度是997,可以在sys里面修改

def hannuo(n,a,b,c):
    if n == 1:
        print(a,'-->',c)
    else:
        hannuo(n-1,a,c,b)#把n-1层放到b
        print(a,'-->',c)#把最后一层放到c
        hannuo(n-1,b,a,c)#把b上的n-1层放到c

n = int(input('please input one number'))
hannuo(n,'a','b','c')

二分法


l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

def two_search(l):
    n = len(l)
    a = int(input('please input a number'))
    left = 0
    right = n
    while left <= right:
        if l[(left+right)//2] < a:
            left = (left+right)//2
        elif l[(left+right)//2] > a:
            right = (left+right)//2
        elif l[(left+right)//2] == a:
            print('找到了',(left+right)//2+1)
            break

two_search(l)


在不修改原函数的功能的情况下,增加额外的功能,装饰器的返回值也是一个函数对象

import time

def func(fun):
    def inner():
        start = time.time()
        print(start)
        fun()
        print(time.time()-start)
    return inner

@func
def call1():
    print('hello wordl!')

call1()

等同于

import time

def func(fun):
    def inner():
        start = time.time()
        print(start)
        fun()
        print(time.time()-start)
    return inner


def call1():
    print('hello wordl!')

call1 = func(call1)
call1()

带多种参数的装饰器

import time

def func(fun):
    def inner(*args,**kwargs):
        start = time.time()
        print(start)
        fun(*args,**kwargs)
        print(time.time()-start)
    return inner

@func
def call1(*args,**kwargs):
    print(args)
    print(kwargs)

call1(1,5,6,'asdcxsc',[1,555,9590],zhangsan = 666)

但要注意,像上面这种写法,装上装饰器之后,原函数里面的相关信息(如注释、函数名称)等就会失效,如果想要保留这些信息,则需要用到wrapper装饰器

import time
from functools import wraps
def func(fun):
    @wraps(fun)
    def wrapper(*args,**kwargs):
        start = time.time()
        print(start)
        fun(*args,**kwargs)
        print(time.time()-start)
    return wrapper

@func
def call1(*args,**kwargs):
    '''sssss'''
    print(args)
    print(kwargs)

call1(1,5,6,'asdcxsc',[1,555,9590],zhangsan = 666)

print(call1.__doc__)

# 1638601036.3845785
# (1, 5, 6, 'asdcxsc', [1, 555, 9590])
# {'zhangsan': 666}
# 0.0
# sssss

带控制的装饰器

import time
# from functools import wraps
def outer(flag):
    def func(fun):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                print(start)
                fun(*args,**kwargs)
                print(time.time()-start)
        return inner
    return func

@outer(True)
def call1(*args,**kwargs):
    '''sssss'''
    print(args)
    print(kwargs)

call1(1,5,6,'asdcxsc',[1,555,9590],zhangsan = 666)

动态规划的思想是把一个大问题拆分成一个个小问题,并在解决这些小问题之后把其最优解保留下来,解后面的大问题时会用到这些小问题的解

例一:01背包:现有音响(3000元,重4),电脑(2000元,重3),吉他(1500元,重1),你有一个能装最大重量为4的背包,现在请找出能够获取最大利益的装货方式

一开始我们只考虑吉他,这种情况下,背包容量从1-4的最优装法都只有装入吉他这一种,最终的解为(1500)

avatar

接下来我们把音响也加入考虑,当背包容量在1-3的时候,依旧是只有拿吉他这种解法,但当容量到4的时候,这时候选择往背包里面装入音响比装入吉他利益要来的更高,所以我们在4这一格选择就放入音响,得到了这一行的结果

avatar

接下来我们把电脑加入考虑,当背包容量是1-2的时候,依旧还是拿吉他(1500),但当变成3的时候,我们发现选择拿电脑更合适(2000),而到4的时候,我们发现,如果拿电脑,我们还余下1的余量,而余量1的最优解是1500,于是我们同时拿了电脑和吉他,共3500,大于只拿音响的3000,于是最终解变成了电脑与吉他

avatar

我们不难发现,其实celli=max{celli-1,price[i]+celli-1](即当前物品价值加上剩余空间最大价值)},在计算时我们用到了前面的计算结果

例二:最大子段和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

思路:采用动态规划法,每一个元素都有以其为结尾的数组,这个数组的最大值取值有两种情况:如果前面以num[i-1]为结尾的数组大于零,则他的值等于前面那个数组的值加上自身,如果前面那个数组小于零,则这个数组的最大值就是这个元素本身,即sum[i]=max{sum[i-1]+num[i],num[i]},当整个数组遍历完,返回sum数组里面的最大值

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        length = len(nums)
        sum = [ i  for i  in range(length)]
        sum[0] = nums[0]
        if length > 0:
            for i in range(1,length):
                if sum[i-1] > 0:
                    sum[i] = sum[i-1] + nums[i]
                else:
                    sum[i] = nums[i]
            return max(sum)
        else:
            return nums[0]