9.4  设置用户权限

  用户权限主要是对不同的用户设置不同的功能使用权限,而每个功能主要以模型来划分。以9.3节的MyDjango项目为例,在Admin后台管理系统可以查看并设置用户权限,如下图:

用户权限设置

  上图左边列表框中列出了整个项目的用户权限,以user|用户|Can add user为例:

    1、user代表项目的App。

    2、用户代表App所定义的模型MyUser。

    3、Can add user代表该权限可对模型MyUser执行新增操作。

  一般情况下,在执行数据迁移时,每个模型默认拥有增(add), 改(change),删(delete)权限。数据迁移完成后,可以在数据库中查看数据表auth_permission的数据信息,每条数据信息代表项目中某个模型的某个权限,如下图:

  设置用户权限实质上是对数据表user_myuser和auth_permission之间的数据设置多对多关系。首先需要了解用户、用户权限和用户组三者之间的关系,以MyDjango的数据表为例,如下图:

  从整个项目的数据表可以看到,用户、用户权限和用户组分别对应数据表user_myuser、auth_permission和auth_group。无论是设置用户权限、设置用户所属用户组还是设置用户组的权限,其实质都是对两个数据表之间的数据建立多对多的数据关系,说明如下:

    1、数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置。

    2、数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户。

    3、数据表auth_group_permissions:管理数据表auth_group和auth_permission之间的多对多关系,实现用户组设置权限。

  实现用户的权限设置需要注意:如贵哦用户角色是超级用户,该用户是无须设置权限的,用户权限只适用于非超级用户。我们在PyCharm的Terminal下开启Django的shell模式来实现用户权限设置,代码如下:

(py3_3) E:\test5\MyDjango>python manage.py shell

#导入模型MyUser
In [1]: from user.models import MyUser
#查询用户信息,filter查询返回列表格式,因此设置列表索引获取User对象
In [3]: user = MyUser.objects.filter(username='user1')[0]
#判断当前用户是否具有权限add_product
#index.add_product为固定写法,index为项目的App名,add_product是数据表auth_permission的字段codename
In [4]: user.has_perm('index.add_product')
Out[4]: False #导入模型Permission
In [5]: from django.contrib.auth.models import Permission #在权限管理表获取权限add_product的数据对象permission
In [7]: permission = Permission.objects.filter(codename='add_product')[0] #对当前用户对象user设置权限add_product
In [10]: user.user_permissions.add(permission) #再次判断当前用户是否具有权限add_product
In [12]: user.has_perm('index.add_product')
Out[12]: True

  上述代码对用户名为user1的用户设置了产品信息的新增权限,打开数据表user_myuser_user_permissions可以看到新增了一条数据,如下图:

数据表user_myuser_user_permissions

  数据表的字段myuser_id和permission_id分别是数据表user_myuser和auth_permission的主键,如上图上的每一条数据代表某个用户具有某个模型的某个操作权限。除了添加权限之外,还可以对用户的权限进行删除和查询,代码如下:

In [6]: user = MyUser.objects.filter(username='user1')[0]

In [10]: permission = Permission.objects.filter(codename='add_product')[0]

#删除某条权限
In [11]: user.user_permissions.remove(permission)
#判断是否已删除权限,若为False,说明删除成功。函数has_perm用于判断用户是否拥有权限
In [12]: user.has_perm('index.add_product')
Out[12]: False #清空当前用户全部权限
In [13]: user.user_permissions.clear() #获取当前用户所拥有的权限信息
#将上述删除的权限添加到数据表再查询
In [14]: user.user_permissions.add(permission) In [15]: user.user_permissions.values()
Out[15]: <QuerySet [{'id': 25, 'name': 'Can add product', 'content_type_id': 7, 'codename': 'add_product'}]>

9.5  自定义用户权限

  一般情况下,每个模型默认拥有增(add),改(change),删(delete)权限。但实际开发中,可能要对某个模型设置特殊的权限,比如设置访问权限。为了解决这种情况,在定义模型的时候,可以在模型的Meta中设置自定义权限。以MyDjango为例,对index的模型Product重新定义,代码如下:

#index/models.py
class Product(models.Model):
id = models.AutoField('序号', primary_key=True)
name = models.CharField('名称',max_length=50)
weight = models.CharField('重量',max_length=20)
size = models.CharField('尺寸',max_length=20)
type = models.ForeignKey(Type, on_delete=models.CASCADE,verbose_name='产品类型')
# 设置返回值
def __str__(self):
return self.name class Meta:
#自定义权限
permissions = (
('visit_Product', 'Can visit Product'),
)

  定义模型Product的时候,通过重写父类models.Model的permissions属性可实现自定义用户权限。该属性以元组或列表的数据格式表示,每个元素代表一个权限,也是以元组或列表表示。在一个权限中含有两个元素,如('add_Product', 'Can create Product'),add_product和Can create Product分别是数据表auth_permission的codename和name字段。

  在数据库中清除MyDjango原有的数据表,并在PyCharm的Terminal中重新执行数据迁移,指令代码如下:

(py3_3) E:\test5\MyDjango>python manage.py makemigrations

(py3_3) E:\test5\MyDjango>python manage.py migrate

  指令执行完成后,在数据库中打开数据表auth_permission,可以找到自定义权限visit_Product,如下图:

自定义全visit_Product截图

9.6  设置网页的访问权限

  本节中,结合实际的例子讲述如何在实际开发中使用用户权限,以MyDjango为例,数据表auth_permission已自定义权限visit_Product,数据表user_myuser分别创建了一名超级用户和一名普通用户,如下图:

数据表user_myuser的用户信息

  本例需要将项目的index和user结合使用。index主要将权限应用到开发中,而user主要用于用户的注册、登录和退出登录,用于检验index的应用效果。

  首先讲解user的开发流程,我们分别对路由urls.py、视图views.py和模板user.html进行相应开发,共同完成用户的注册、登录和退出登录,代码如下:

#路由user/urls.py
from django.urls import path
from . import views urlpatterns = [
#用户登录
path('login.html', views.loginView, name='login'),
#用户注册
path('register.html', views.registerView, name='register'), #退出登录
path('logout.html', views.logoutView, name='logout'),
] #视图user/views.py
from django.shortcuts import render, redirect
from .models import MyUser
from django.contrib.auth.models import Permission
from django.contrib.auth import login, authenticate, logout # 用户登录
def loginView(request):
tips = '请登录'
title = '用户登录'
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
if MyUser.objects.filter(username=username):
user = authenticate(username=username, password=password)
if user:
if user.is_active:
# 登录当前用户
login(request, user)
return redirect('/')
else:
tips = '账号密码错误,请重新输入'
else:
tips = '用户不存在,请注册'
return render(request, 'user.html', locals()) # 用户注册
def registerView(request):
title = '用户注册'
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
if MyUser.objects.filter(username=username):
tips = '用户已存在'
else:
user = MyUser.objects.create_user(username=username, password=password)
user.save()
# 添加权限
permission = Permission.objects.filter(codename='visit_Product')[0]
user.user_permissions.add(permission)
return redirect('/user/login.html')
return render(request, 'user.html', locals()) # 退出登录
def logoutView(request):
logout(request)
return redirect('/')
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
<div class="container">
<div class="flex-center">
<div class="unit-1-2 unit-1-on-mobile">
<h1>MyDjango Auth</h1>
{% if tips %}
<div>{{ tips }}</div>
{% endif %}
<form class="form" action="" method="post">
{% csrf_token %}
<div>用户名:<input type="text" name='username'></div>
<div>密 码:<input type="password" name='password'></div>
<button type="submit" class="btn btn-primary btn-block">确定</button>
</form>
</div>
</div>
</div>
</div>
</body>
</html>

  上述代码主要实现一个简单的操作流程,流程顺序为用户注册->用户登录->访问首页,具体实现过程如下:

    1、首先用户访问用户注册界面,输入新的用户信息并单击"确定"按钮,提交用户注册信息到网站后台。

    2、后台的视图函数registerView接收表单数据,判断当前注册的用户是否存在。如果用户不存在,将表单数据保存到数据表user_myuser中,创建新的用户信息。

    3、默认情况下,新创建的用户是没有设置任何权限的,视图函数对新创建的用户设置visit_Product权限。注册成功后,程序会自动跳转到用户登录界面。

    4、在用户登录界面输入新创建的用户信息,完成用户登录后,程序会自动跳转到网站的首页。

  在user中实现了用户的权限设置,为新创建的用户添加visit_Product权限,接着在index中实现用户权限的校验。在index的路由urls.py、视图views.py和模板index.html中分别编写以下代码:

#index/urls.py
from django.urls import path
from . import views
urlpatterns = [
# 首页的URL
path('', views.index),
] #index/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required, permission_required # 使用login_required和permission_required分别对用户登录验证和用户权限验证
@login_required(login_url='/user/login.html')
@permission_required(perm='index.visit_Product', login_url='/user/login.html')
def index(request):
return render(request, 'index.html', locals())

  在视图函数index中使用了装饰器login_required和permission_required,分别对当前用户的登录状态和用户权限进行校验,说明如下:

    login_required:设置用户登录访问权限。如果当前用户尚未在用户登录界面完成登录而直接访问首页,程序自动跳转到登录界面,只有用户完成登录后才能访问首页。login_required的参数有redirect_field_name和login_url。

      1、参数redirect_field_name:默认值是next。当登录成功之后,程序会自动跳回之前浏览的网页。

      2、参数login_url:设置登录界面的URL地址。默认值是settings.py的属性LOGIN_URL,而属性LOGIN_URL需要开发者自行在settings.py中配置。

    permission_required:验证当前用户是否拥有相应的权限。若用户没有使用权限,程序会跳转到登录界面或者抛出异常。permission_required的参数如下。

      1、参数perm:必须参数,判断当前用户是否拥有权限。参数值为固定格式,如index.visit_Product,index为项目的App名,visit_product来自数据表auth_permission的字段codename。

      2、参数login_url:设置登录界面的URL地址,默认值为None。若不设置参数,验证失败后会抛出404异常。

      3、参数raise_exception:设置抛出异常,默认值为False。

    装饰器permission_required的作用与内置函数has_perm相同,上述代码也可以使用函数has_perm实现装饰器permission_required的功能,代码如下:

#使用函数has_perm实现装饰器permission_required功能
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required @login_required(login_url='/user/login.html')
def index(request):
user = request.user
if user.has_perm('index.visit_Product'): return render(request, 'index.html', locals())
else:
return redirect('/user/login.html')

  最后在模板index.html中实现用户权限判断,这也是权限校验的使用方法之一。模板index.html的<header>标签代码修改如下:

<header id="top">
<!-- 内容显示区域 :width : 1211px -->
<div id="top_box">
<ul class="lf">
<li><a href="#">华为官网</a></li>
<li><a href="#">华为荣耀</a></li>
</ul>
<ul class="rt">
{#在模版中使用user变量是一个User或者AnoymousUser对象,该对象由模型MyUser实例化#}
{% if user.is_authenticated %}
<li>用户名: {{ user.username }}</li>
<li><a href="{% url 'logout' %}">退出登录</a></li>
{% endif %}
{#在模版中使用perms变量是Permission对象,该对象由模型Permission实例化#}
{% if perms.index.add_product %}
<li>添加产品信息</li>
{% endif %}
</ul>
</div>
</header>

  在模板index.html中分别使用变量user和perms,但从视图函数index总可以发现,视图函数并没有将变量user和perms传递给模板。其实变量user和perms是由Django自动生成的,变量的生成与配置五年级settings.py的TEMPLATES设置有关,我们查看setting.py的TEMPLATES配置信息,代码如下:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'index/templates'),
os.path.join(BASE_DIR, 'user/templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

  因为TEMPLATES中定义了处理器集合context_processors,所以在解析模板Template之前,Django首先依次运行处理器集合的程序。当运行到处理器django.contrib.auth.context_processors.auth时,程序会生成变量user和perms,并且将变量传入模板变量TemplateContext中,所以在模板中可以直接使用变量user和perms。

  从上述例子可以看到,项目的user主要实现权限的设置功能;项目的index主要实现权限的使用,权限的使用主要判断当前用户是否具有权限的使用资格,而权限的判断可以从视图函数或模板语法实现。在浏览器上分别使用超级用户和普通用户登录网站,两者的首页信息如下图:

9.7  设置用户组

  顾明思义,用户组就是对用户进行分组管理,其作用是在权限控制中可以批量地对用户的权限进行分配,而不同一个一个地按用户组所分配的所有权限。例如用户组teachers拥有权限can_create_lesson,那么所有属于teachers的用户都会有can_create_lesson权限。

  我们知道用户、权限和用户组三者之间是多对多的数据关系,而用户组可以理解为用户和权限之间的中转站。设置用户组分为两个步骤:设置用户组的权限和设置用户组的用户。

  设置用户组的权限主要对数据表auth_group和auth_permission构建多对多的数据关系,数据关系保存在数据表auth_group_permissions中。以MyDjango为例,其数据库结构如下图所示:

数据库结构

  在数据表auth_group中创建三条数据信息:产品信息、产品类型和用户管理,每条信息在项目中代表一个用户组,如下图:

数据表auth_group

  我们在PyCharm的Terminal中使用Django的shell模式来实现用户组的权限配置,代码如下:

#用户组的权限配置
#导入内置模型Group和Permission
(py3_3) E:\test5\MyDjango>python manage.py shell In [1]: from django.contrib.auth.models import Group In [2]: from django.contrib.auth.models import Permission #获取某个权限对象permission
In [3]: permission = Permission.objects.get(codename='visit_Product') #获取某个用户组对象group
In [4]: group = Group.objects.get(id=1) #将权限permission添加到用户组group中
In [5]: group.permissions.add(permission)

  上述代码将visit_Product权限添加到用户组(产品信息),功能实现过程如下:

    1、从数据表auth_group获取用户组(产品信息)对象group,对象group代表数据表总某一条数据。

    2、从数据表auth_permission获取权限(visit_Product)对象permission,对象permission代表数据表中某一条数据。

    3、使用permissions.add方法将权限对象permission与用户组对象group构建多对多数据关系并保存在数据表auth_group_permissions中。查看数据表auth_group_permissions,数据信息如下图:

  

数据表auth_group_permissions

  除了添加用户组的权限之外,还可以删除用户组已有的权限,代码如下:

#删除当前用户组group的visit_Product权限
In [6]: group.permissions.remove(permission)
#删除当前用户组group的全部权限
In [7]: group.permissions.clear()

  设置用户组的用户主要对数据表auth_group和user_myuser构建多对多数据关系,数据关系保存在数据表user_myuser_groups中。在Django的shell模式下实现用户组的用户设置,代码如下:

#将用户分配到用户组
#导入模型Group和MyUser
In [8]: from user.models import MyUser In [9]: from django.contrib.auth.models import Group #获取用户对象user,对象user代表用户名为user1的数据信息
In [11]: user = MyUser.objects.get(username='user1') #获取用户组对象group,对象group代表用户组(产品信息)的数据信息
In [13]: group = Group.objects.get(id=1) #将用户添加到用户组
In [14]: user.groups.add(group)

  上述代码将用户名为user1的用户添加到用户组(产品信息),功能实现过程与用户组的权限设置是相似的,只不过两者所使用的模型有所不同。查看数据表user_myuser_groups,数据信息如下图:

数据表user_myuser_groups

  除了添加用户组的用户之外,还可以删除用户组已有的用户,代码如下:

#删除用户组某一用户
In [15]: user.groups.remove(group)
#情况用户组全部用户
In [16]: user.groups.clear()

9.8  本章小结

  Django除了有强大的Admin管理系统之外,还提供了完善的用户管理系统。整个用户管理系统可分为三大部分:用户信息、用户权限和用户组,在数据库中分别对应数据表auth_user、auth_permission和auth_group。

  使用内置模型User和内置的函数可以快速实现用户管理功能,如用户注册、登录、密码修改、密码找回和用户注销。模型User的字段说明以及常用的内置函数如下。

模型User字段及说明

字段 说明
ID int类型,数据表主键
Password varchar类型,代表用户密码,在默认情况下使用pbkdf2_sha256方式来存储和管理用户的密码
last_login datetime类型,最近一次登录的时间
is_superuser tinyint类型,表示该用户是否拥有所有的权限,即是否为超级用户
Username varchar类型,代表用户账号
first_name varchar类型,代表用户的名字
last_name varchar类型,代表用户的姓氏
Email varchar类型,代表用户的邮件
is_staff 用来判断用户是否可以登录进入Admin系统
is_active tinyint类型,用来判断该账户的状态是否被激活
date_joined datetime类型,账号的创建时间

常用的内置函数及说明

内置函数 说明
authenticate 验证用户是否存在,必选参数为username和password,只能用于模型User
create_user 创建新的用户信息,必选参数为username,只能用于模型User
set_password 修改用户密码,必选参数为password,只能用于模型User
login/logout 用户的登录和注销,只能哟农户模型User
make_password 密码加密处理,必选参数为password,可脱离模型User单独使用
check_password 检验加密前后的密码是否相同,可脱离模型User单独使用
email_user 发送邮件,只能用于模型User
send_mail 发送邮件
send_mass_mail 批量发送邮件
EmailMultiAlternatives 发送自定义内容格式的邮件

  Django提供了4中模型扩展的方法:

    1、代理模型:这是一种模型继承,这种模型在数据库中无须创建新数据表。一般用于改变现有模型的行为方式,如增加新方法函数等,并且不影响现有数据库的结构。当不需要在数据库中存储额外的信息,而需要增加操作方法或更改模型的查询管理方式时,适合使用代理模型来扩展现有User模型。

    2、Profile扩展模型User:当存储的信息与模型User相关,而且并不改变模型User原有的认证方法时,可定义新的模型MyUser,并设置某个字段为OneToOneField,这样能与模型User形成一对一关联,该方法称为用户配置(User Profile)。

    3、AbstractBaseUser扩展模型User:当模型User的内置方法并不符合开发需求时,可使用该方法对模型User重新自定义设计,该方法对模型User和数据库架构影响很大。

    4、AbstractUser扩展模型User:如果模型User的内置的方法符合开发需求,在不改变这些函数方法的情况下,添加模型User的额外字段,可通过AbstractUser方式实现。使用AbstractUser定义的模型会替换原有模型User。

  用户、用户权限和用户组分别对应数据表user_myuser、auth_permission和auth_group。无论是设置用户权限、设置用户所属用户组还是设置用户组的权限,其实质都是对两个数据表之间的数据建立多对多的数据关系,说明如下:

    1、数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置。

    2、数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户。

    3、数据表auth_group_permissions:管理数据表auth_group和auth_permission之间的多对多关系,实现用户组设置权限。

玩转Django2.0---Django笔记建站基础九(二)(Auth认证系统)的更多相关文章

  1. 玩转Django2.0---Django笔记建站基础九(一)(Auth认证系统)

    第九章 Auth认证系统 Django除了有强大的Admin管理系统之外,还提供了完善的用户管理系统.整个用户管理系统可分为三大部分:用户信息.用户权限和用户组,在数据库中分别对应数据表auth_us ...

  2. 玩转Django2.0---Django笔记建站基础十一(二)((音乐网站开发))

    11.5 歌曲排行榜 歌曲排行榜是通过首页的导航链接进入的,按照歌曲的播放次数进行降序显示.从排行榜页面的设计图可以看到,网页实现三个功能:网页顶部搜索.歌曲分类筛选和歌曲信息列表,其说明如下: 1. ...

  3. 玩转Django2.0---Django笔记建站基础十二(Django项目上线部署)

    第十二章 Django项目上线部署 目前部署Django项目有两种主流方案:Nginx+uWsGI+Django或者Apache+uWSGI+Django.Nginx作为服务器最前端,负责接收浏览器的 ...

  4. 玩转Django2.0---Django笔记建站基础十(二)(常用的Web应用程序)

    10.3 CSRF防护 CSRF(跨站请求伪造)也成为One Click Attack或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用,窃取网站的用户信息来制作 ...

  5. 玩转Django2.0---Django笔记建站基础十三(第三方功能应用)

    第13章 第三方功能应用 在前面的章节中,我们主要讲述Django框架的内置功能以及使用方法,而本章主要讲述Django的第三方功能应用以及使用方法.通过本章的学习,读者能够在网站开发过程中快速开发网 ...

  6. 玩转Django2.0---Django笔记建站基础八(admin后台系统)

    第八章 admin后台系统 admin后台系统也成为网站后台管理系统,主要用于对网站前台的信息进行管理,如文字.图片.影音和其他日常使用文件的发布.更新.删除等操作,也包括功能信息的统计和管理,如用户 ...

  7. django笔记 - 建站

    1,建站步骤:1)django-admin.exe startproject mysite 创建完后的目录结构: - mysite # 对整个程序进行配置 - init - settings # 配置 ...

  8. 玩转Django2.0---Django笔记建站基础十(一)(常用的Web应用程序)

    第十章 常用的Web应用程序 Django为开发者提供了常见的Web应用程序,如会话控制.高速缓存.CSRF防护.消息提示和分页功能.内置的Web应用程序大大优化了网站性能,并且完善了安全防护机制,而 ...

  9. 玩转Django2.0---Django笔记建站基础六(模型与数据库)

    第六章 模型与数据库 Django对各种数据库提供了很好的支持,包括:PostgreSQL.MySQL.SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架. ...

随机推荐

  1. 牛客小白月赛15A 斑羚飞渡

    链接:https://ac.nowcoder.com/acm/contest/917/A 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262144K 64b ...

  2. 2019-8-31-git-上传当前分支

    title author date CreateTime categories git 上传当前分支 lindexi 2019-08-31 16:55:59 +0800 2018-05-08 09:2 ...

  3. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  4. python OrderedDict

    15年16年接触python时候,还不知道这个函数,只知道dict的无序,造成了一些麻烦 今天view 代码,发现了 OrderedDict() 在python2.7中比较吃内存 pop(获取指定ke ...

  5. TestStand 基本设置

    1. 过程模型设置 菜单->Configure->Station Options->Model TestStand 默认提供了三种过程模型 Sequential.Batch.Para ...

  6. [梁山好汉说IT] 以水浒传为例讲解贝叶斯定理

    0x00 摘要 看看呼延灼如何利用贝叶斯定理来判断 "自己是否是公明哥哥的心腹". 0x01 IT概念 1. 贝叶斯定理 贝叶斯定理是用来解决"逆概率"问题的, ...

  7. vue-awesome-swiper手动滑动后不再自动轮播的问题

    <swiper :options="swiperOption" ref="mySwiper" > <!--轮播图内容--> </s ...

  8. 从头学pytorch(十一):自定义层

    自定义layer https://www.cnblogs.com/sdu20112013/p/12132786.html一文里说了怎么写自定义的模型.本篇说怎么自定义层. 分两种: 不含模型参数的la ...

  9. 【题解】Comet OJ 国庆欢乐赛 简要题解

    [题解]Comet OJ 国庆欢乐赛 简要题解 A 直接做 B 直接做,结论: \[ ans=\max([Max\ge \mathrm{sum}] Max,s[n]/2) \] C 考虑这样一个做法: ...

  10. Linux三剑客之sed的基本用法介绍

    [介绍] sed是一款强大的非交互式的文本编辑器,可以对文件文本进行增删改查的相关操作,本文主要是讲解以下sed的基本用法. [常用选项] -e 下一个参数为一个sed指令,一般只会用于同一行有多个s ...